Perl入学式に参加した感想&その後ちょっと作ったMojoliciousのサイト
Perl入学式 Advent Calendar 2014の12月16日(火)の記事です。
昨日はpapixさんのReplyでお手軽にPerlのコードを動かす話でした。
Perlの対話型環境は始めて聞きました。ちょっと触ってみようかと思います。
ここではPerl入学式への参加したことやその感想などを記載していきます。
あとついでに作ったサイト(超しょぼい)の説明とか…
入学式について
参加してよかったこと
Perlについて本当の基礎から学ぶことができた。
正規表現が組めないと使えないイメージしかないからなかなか手を付けることが出来なかった。
入学式に参加して基礎から学ぶ機会を与えられたのでPerlについて興味をもつきっかけを得ることができました。
まだ、あんまり理解していないけど…
本当に最初から学ぶことができる
プログラミングの初心者でも他の言語を知ってても最初から学べる。内容によっては時間が足りないこともあるのがネックかな?と思うくらい。
サポーターが意外と多い
ハンズオンとかの場合は大抵2~3人、または4~5人辺りでしたけど私が参加した時は入学式参加者全員がすぐに聞ける状態でしたのでわからないことはすぐに聞きやすかったと思います。
2014年度は参加は未定中
基本、2013年のYAPCから参加し始めて最後までいたので独学でできそうなところは自分でなんとかしたほうがいいと思いましたし、勉強会の空き席の状況がほとんどなかったので盛況なんだなと思いました。
ただ、他の勉強会がある場合は時間を調整して参加しています。
実は参加するかどうかでかなり悩んだ
IT系のコミュニティとか勉強会とかは私の回りの人間は誰も参加していないので「参加するべきか?」とか「敷居高い?」とか「いまさらやるべきじゃない?」などの考えが結構でて申し込みを行うのは結構ギリギリまて時間をかけてしまいました。
作ったWebサイト
注意
期待しないで、想像しているより300%以上しょぼいです。
どんなサイト
8月下旬に痛風になってしまいまして。プリン体ってなんぞや?ということから同じように痛風になっている人やプリン体がどんなものに含まれているのかを軽くまとめたサイトです。専門的な知識はないのでいくつかのサイトを巡って得た情報を出してるだけですけど…
作成する上でベースとしたもの
アプリケーション構成
以下のコマンドで簡単なアプリを構成
mojo generate app Tufu::Web
ソースコードは実際
https://github.com/mshige1979/tufuapi
を見たほうが速いかも
ファイル構成
. ├── config.pl ├── env │ ├── sass │ │ ├── config.rb │ │ ├── images │ │ ├── sass │ │ │ └── app.scss │ │ └── stylesheets │ │ ├── ie.css │ │ ├── print.css │ │ └── screen.css │ └── sql │ ├── alter.sql │ ├── beer_insert.sql │ ├── ddl.sql │ └── food_insert2.sql ├── lib │ └── Tufu │ ├── Config │ │ └── App.pm │ ├── DB │ │ └── Schema.pm │ ├── DB.pm │ ├── Model │ │ ├── App.pm │ │ ├── Beer.pm │ │ ├── Food.pm │ │ └── StatisticsNum.pm │ ├── Model.pm │ ├── Web │ │ ├── App.pm │ │ └── Root.pm │ └── Web.pm ├── log ├── public │ ├── css │ │ ├── app.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ └── bootstrap-theme.min.css │ ├── favicon.ico │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── icon_image.png │ ├── img │ │ ├── draft_beer_t.png │ │ └── tama02.jpg │ └── js │ ├── angular-animate.js │ ├── angular-animate.min.js │ ├── angular-animate.min.js.map │ ├── angular.js │ ├── angular.min.js │ ├── angular.min.js.map │ ├── angular-resource.js │ ├── angular-resource.min.js │ ├── angular-resource.min.js.map │ ├── angular-route.js │ ├── angular-route.min.js │ ├── angular-route.min.js.map │ ├── angular-touch.js │ ├── angular-touch.min.js │ ├── angular-touch.min.js.map │ ├── app.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-2.1.1.js │ ├── jquery-2.1.1.min.js │ └── jquery-2.1.1.min.map ├── script │ └── tufu_web ├── t │ └── basic.t └── templates ├── exception.production.html.ep ├── layouts │ └── default.html.ep ├── not_found.production.html.ep └── root ├── index.html.ep ├── item1.html.ep ├── item2.html.ep └── main.html.ep
liteじゃないほうでMojoliciousを作成したほうがテンプレートのファイルなどがわかれているので管理はし易いと思います。
それにしても実際使用していないファイルが結構あるw
実装を一部記載
ここで簡単にコントローラーのルーティングの設定やキャッシュ設定を行いました
lib/Tufu/Web.pm
package Tufu::Web; use Mojo::Base 'Mojolicious'; # This method will run once at server start sub startup { my $self = shift; # Documentation browser under "/perldoc" $self->plugin('PODRenderer'); $self->app->hook(before_routes => sub { my $c = shift; $c->req->headers->if_modified_since( 'Thu, 01 Jun 1970 00:00:00 GMT' ); }); # Router my $r = $self->routes; # Normal route to controller $r->get('/')->to('root#index'); $r->get('/templates/main.html')->to('root#main'); $r->get('/templates/item1.html')->to('root#item1'); $r->get('/templates/item2.html')->to('root#item2'); # api用 $r->get('/api/food')->to('app#food'); $r->get('/api/beer')->to('app#beer'); $r->get('/api/dataGraph')->to('app#dataGraph'); # 画面をリロードした場合の対策 $r->get('/item1')->to('root#item'); $r->get('/item2')->to('root#item');
データベース設定
Tengなどを使用するので定義
lib/Tufu/DB.pm
package Tufu::DB; use parent 'Teng'; __PACKAGE__->load_plugin('SearchBySQLAbstractMore'); 1;
データベースのスキーマ定義
Tengで使用するためのテーブルを設定
lib/Tufu/DB/Schema.pm
package Tufu::DB::Schema; use strict; use warnings; use Teng::Schema::Declare; use utf8; use Encode; table{ name 'food'; pk 'id'; columns qw/id kind item_name prin_value unit_name/; }; table{ name 'beer'; pk 'id'; columns qw/id maker kind item_name alcohol_content prin_value unit_name/; }; table{ name 'statistics_num'; pk 'year'; columns qw/year num_gk num_male num_female/; }; 1;
モデル設定
接続処理などの共通部分を設定
lib/Tufu/Model.pm
package Tufu::Model{ use Mouse; use Tufu::DB; use Tufu::Config::App; has 'db' => ( is => 'ro', isa => 'Tufu::DB', lazy_build => 1 ); has 'connect_info' => ( is => 'ro', isa => 'ArrayRef', lazy_build => 1 ); sub _build_connect_info{ my $self = shift; Tufu::Config::App::config->{connect_info}; } sub _build_db{ my $self = shift; Tufu::DB->new( connect_info => $self->connect_info ); } __PACKAGE__->meta->make_immutable(); } 1;
lib/Tufu/Web/App.pm
package Tufu::Web::App; use Mojo::Base 'Mojolicious::Controller'; use Tufu::Model::Food; use Tufu::Model::Beer; use Tufu::Model::StatisticsNum; use Data::Dumper; sub food { # パラメータ指定 my $self = shift; my $log = $self->app->log; $log->debug("food start"); my $model = new Tufu::Model::Food(); my $list = $model->find(); $log->debug(Dumper($list)); $log->debug("food end"); # json指定 $self->render(json => $list); } sub beer { # パラメータ指定 my $self = shift; my $log = $self->app->log; $log->debug("beer start"); my $model = new Tufu::Model::Beer(); my $list = $model->find(); $log->debug(Dumper($list)); $log->debug("beer end"); # json指定 $self->render(json => $list); } sub dataGraph { # パラメータ指定 my $self = shift; my $log = $self->app->log; $log->debug("dataGraph start"); my $model = new Tufu::Model::StatisticsNum(); my $list = $model->find(); $log->debug(Dumper($list)); $log->debug("dataGraph end"); $self->render(json => $list); } 1;
データ取得モデル
lib/Tufu/Model/Beer.pm
package Tufu::Model::Beer{ use Mouse; use Tufu::Model::App; extends Tufu::Model::App; has 'table' => ( is => 'ro', isa => 'Str', default => 'beer' ); sub find{ my ($self) = @_; my $data; my $list = []; # 全件取得 $data = $self->db->search($self->table, {}); # ハッシュ型で設定 while(my $row = $data->next()){ push @{$list}, { id => $row->id, maker => $row->maker, kind => $row->kind, item_name => $row->item_name, alcohol_content => $row->alcohol_content, prin_value => $row->prin_value, unit_name => $row->unit_name }; } # 結果返却 return $list; } __PACKAGE__->meta->make_immutable(); }
ついでにjsも
app.js
google.load('visualization', '1', { packages: ['corechart'] }); google.setOnLoadCallback(function() { angular.bootstrap(document.body, ['tufuApp']); }); var tufuApp = angular.module('tufuApp', ['ngRoute', 'ngAnimate']); tufuApp.config(function($routeProvider, $locationProvider){ $routeProvider.when('/', { templateUrl: "templates/main.html", controller: MainController }).when('/item1', { templateUrl: "templates/item1.html", controller: Page1Controller }).when('/item2', { templateUrl: "templates/item2.html", controller: Page2Controller }).otherwise({ redirectTo: '/' }); }); tufuApp.config(function($locationProvider){ $locationProvider.html5Mode({ enabled: true, requireBase: false }); }); tufuApp.controller('NaviController', NaviController); tufuApp.controller('GraphController', GraphController); function MainController($scope, $http){ } function Page1Controller($scope, $http){ $http({ method: 'get', url: '/api/food', withCredentials: true }).success(function(data) { $scope.food_list = data; }).error(function(data, status) { alert('通信エラーが発生しました'); }); } function Page2Controller($scope, $http){ $http({ method: 'get', url: '/api/beer', withCredentials: true }).success(function(data) { $scope.beer_list = data; }).error(function(data, status) { alert('通信エラーが発生しました'); }); } function NaviController($scope){ $scope.link = function(){ location.href = "/"; } } function GraphController($scope, $http){ $http({ method: 'get', url: '/api/dataGraph', withCredentials: true }).success(function(dataList) { var data = new google.visualization.DataTable(); data.addColumn('string', '年'); data.addColumn('number', '合計'); data.addColumn('number', '男性'); data.addColumn('number', '女性'); data.addRows( dataList ); var ac = new google.visualization.ComboChart(document.getElementById('chart_div')); ac.draw(data, { "title" : '通院者数推移(千人)', "hAxis": { "title": "年" }, "seriesType": "bars", // 全体は棒グラフ(default='line') "isStacked": true, "series": { "0": {"type": "line"} } // 平均だけ折れ線グラフ }); } ); }).error(function(data, status) { alert('通信エラーが発生しました'); }); }
つまづいたこと
エラー画面どうしよう
▶ templatesにexception.production.html.epとかnot_found.production.html.epで対応しようかな
configファイルにパスワードとか入れるべき?
▶ 環境変数で対応して様子見
angularjsわからん
▶ がんばろう少しずつ理解していくようにする
内容とかデザインしょぼい(´・ω・`)
▶ センスって重要ですな
おまけ
アドベントカレンダーが始まったのである程度のデータを集めてサイトを作成
https://serene-springs-4867.herokuapp.com/
※遅いです
おまけまーくつー
http://app1.mshige1979tools1.net/
※使ってて虚しくなります