Upload
charsbar
View
6.042
Download
0
Embed Size (px)
DESCRIPTION
Hokkaido.pm #4
Citation preview
Mojolicious::Liteを使ってみよう
February 19, 2011
Hokkaido.pm #4
Kenichi Ishigaki (charsbar)
はじめに
Hokkaido.pm #4 の午前の部では Mojolicious::Lite を使って簡単なウェブアプリケーショ
ンをつくってみます。わからないことがあったら遠慮なく質問してください。また、ある
程度わかっている方はどんどん先に進んでいただいて結構です。
なお、今回の講習ではほとんどの作業をコマンドプロンプト/シェルから行います。みな
さんご存じと思いますが、Windowsをお使いの方はスタートメニューから「すべてのプロ
グラム」などと書かれたメニューを開き、「アクセサリ」の中に入っている「コマンドプロ
ンプト」(または「Windows PowerShell」)というアプリケーションを、MacOSX を含む
Unix系の方はターミナル、端末等々の名前がついているアプリケーションを起動してくだ
さい。以下、コマンドプロンプトから実行するコマンドについては、下記のように表記し
ます。「>」は Windows のコマンドプロンプトです(Unix系 OSをお使いの方は適宜読み
替えてください)。
(コマンド名) (引数...)
Mojolicious(::Lite)について
Mojolicious(::Lite)は、Perl界でもっとも有名なウェブアプリケーションフレームワークの
ひとつである Catalystの原作者ゼバスティアン・リーデル(Sebastian Riedel)氏が 2008年
から開発しているウェブアプリケーションフレームワークです。過去の経緯については
gihyo.jpの特集記事、連載記事にまとめてありますが、これらはすでに古くなっているので
参考程度にとどめてください。
http://gihyo.jp/dev/feature/01/mojo
http://gihyo.jp/dev/serial/01/modern-perl/0022
いまMojolicious(::Lite)を使う理由としては、たとえば次のようなものがあげられます。
- インストールが簡単
- 昔の CGIスクリプトと同じく、簡単なサイトならファイルひとつで配布可能
- Mojoliciousそのもののインストールも外部依存がないので簡単
- Windows環境でも問題なくインストールできます
- 小規模サイトなら Apacheなどの外部サーバも必要ありません
- サイトの成長にあわせてMojolicious::LiteからMojoliciousに移行可能
- 簡単なことは簡単にできますし、複雑なことにも対応できます
- ドキュメントも少しずつ充実してきました
- http://mojolicio.us/perldoc
- https://github.com/kraih/mojo/wiki
- http://wiki.livedoor.jp/mojolicious/
- ウェブ標準に敏感で、最近の仕様にもわりと早く追随してくれます
- WebSocketとかHTML5とか
一方で、このような批判もありました。
- 開発中の仕様変更やファイルの再配置が多かった
- 連載記事などのサンプルコードには半年ともたず古びたものもありました
- バージョン 1.0になったので、今後極端に大きな仕様変更は減ると期待されます
- それでもリーデル氏の過去の言動から安定性を不安視する人はいるのですが…
- 遅い
- まだ十分な最適化が行われていない場所はあるかもしれません
- 必要に応じて外部モジュールで高速化することはそうむずかしくありません
- そもそもどのくらいの速度が必要ですか?
- 独自モジュールが多く学習コストが高い
- 既存の古いモジュールの置き換えがひとつの目的なのである意味仕方ありません
- 必要に応じて外部モジュールを利用することはそうむずかしくありません
この原稿を書いている現在、Mojoliciousの最新版はバージョン 1.1です。お手元のバージ
ョンが古い場合、細かな挙動が異なる可能性がありますので、なるべく最新版に更新して
ください。
今回つくるアプリケーションについて
今回は自宅でも手軽に利用できるものとして、Wiki っぽいアプリケーションをつくってみ
ます。時間も限られていますので、最初は特定のディレクトリ配下のファイルの内容をブ
ラウザ経由で表示・更新できるだけのものをつくり、そこから順に発展させていくことに
しましょう。
初期の要件は以下の通りとします。
- 指定したディレクトリ配下のファイルとサイトの URLが一対一対応するものとします
- 「http://.../html/(ファイル)」でファイルの内容を表示してください
- 「http://.../html/(ファイル)/update」で内容を更新したいです
- 「http://.../html/(ファイル)/delete」でファイルの削除
- 「http://.../html/(ファイル)/create」で新規ファイルを作成
- 「http://.../html/(ディレクトリ)」の場合はファイル一覧を表示しましょう
時間に余裕があったらこのあたりまで対応できるといいですね
- もちろん見栄えはよくしておくにこしたことはありません
- 静的ファイルをいくつか追加しましょう
- PODやmarkdownテキストが含まれていたら HTMLにレンダリングした方がよいかも
- 知らない拡張子の場合は更新できないようにした方が無難でしょう
- バイナリとしてダウンロードさせる手もありそうですが
- 特定のユーザのみ閲覧・更新可能なページがあるといいかも
- ファイルのパーミッションも確認しましょう(読み込み専用コンテンツ)
- 「http://.../api/...」にアクセスしたらコンテンツを JSONで返してほしいです
- 検索もできるにこしたことはありません
- Wikiというなら更新履歴や差分もほしいところでしょう
- ディレクトリをまるごと git管理してみましょうか
- 更新時の衝突回避はどうしましょうか
- XSSや CSRFの対策は十分ですか
- cf. Mojolicious::Plugin::CSRFDefender
(https://github.com/shiba-yu36/p5-Mojolicious-Plugin-CSRFDefender)
Perlと Mojoliciousのインストール
Windows をお使いの方で Perl のインストールが済んでいない方は下記サイトから
ActivePerlないし Strawberry Perlをインストールしてください。
ActivePerl: http://www.activestate.com/activeperl/downloads
Strawberry Perl: http://strawberryperl.com/
Mojolicious(::Lite)は CPANからダウンロードできます。コマンドプロンプトから以下のコ
マンドを実行してください。
(sudo) cpan Mojolicious
また、公式サイトから tarballをダウンロードすることもできます。
http://latest.mojolicio.us/
最新の開発版は githubからチェックアウトしてください。
git clone git://github.com/kraih/mojo
ひな形をつくる
Mojoliciousのインストールが済んだら、適当なディレクトリに移動して、以下のコマンド
を実行してください。myapp.plの部分はお好きな名前に変えていただいて結構です。
mojo generate lite_app myapp.pl
# カレントディレクトリのファイル一覧を表示して、myapp.plというファイルができてい
ることを確認してください。
ブラウザで確認してみよう
Mojolicious::Liteアプリケーションには標準でウェブサーバ機能が用意されています。コマ
ンドプロンプトから以下のコマンドを実行してください。
perl myapp.pl daemon
# ウェブブラウザを起動して、実際にサイトが表示できるか確認してください。
http://localhost:3000
サーバを止めたい場合はコマンドプロンプトで Ctrl+Cなどを入力します。
Plackをインストール済みの方は以下のコマンドも実行してみましょう。
plackup -a myapp.pl
# こちらもウェブブラウザを起動して、実際にサイトが表示できるか確認してください。
http://localhost:5000
ひな形アプリケーションのお役立ち機能
ひな形アプリケーションを起動したあと、下記の URL に移動するとインストール済みの
Mojoliciousのドキュメントを読むことができます(古い Perl をお使いの方は CPAN から
Pod::Simpleの最新版をインストールする必要があるかもしれません)。
http://localhost:3000/perldoc
この機能はおもにMojolicious::Plugin::PodRendererのなかで実装されています。今回のサ
ンプルアプリケーション作りの参考になりそうですね。
確認が済んだら、pod_renderer というプラグインを読み込んでいる行は消してしまってく
ださい。
ふたつの道
ここから先はふたつの道があります。
目で動作確認しながらでないと落ち着かない方はディスパッチャの設定からしてしまいま
しょう。仮テンプレートの作成などが必要になるのでいくらか余計に手間はかかりますが、
実際に動いているのが確認できるので、不慣れなうちはこちらの方が楽しく書けますし、
上司や顧客が相手でも途中経過を見せやすいです。ただし、こちらの道を通ると、なまじ
目チェックが入るせいで、特に異常時のテストがおろそかになりがちですし、どうしても
ウェブの事情を優先してしまいがちなので、あとで拡張に苦労することも多くなります。
また、バグが出たときに問題の切り分けがややむずかしくなります。
ある程度開発に慣れている方ならモデルを書いていく方が早道です。関心を分離しながら
の作業になるので、最終的に表示部分を作るまで人には見せられないのが難点ですが、こ
のモデル部分はウェブの表示以外にも使えますから、自動テストはもとより、データの収
集や加工用のスクリプトなどが必要な場合にも対応しやすくなります。
ディスパッチャ(ルータ)を用意する
Mojolicious::Lite のディスパッチャについては、Mojolicious::Lite のドキュメントのほか、
Mojolicious::Guides::Routingというドキュメントによくまとまっています。ごく基本的な
構成は次の通りです。
get (または post、anyなど) '/(対象となるパス)' => sub { ... };
パスにはさまざまなプレースホルダを利用できます。今回の例ではいちばんゆるいワイル
ドカード型のプレースホルダを利用するのが楽でしょう。サブルーチンの中身はひとまず
最初に用意されていた「/welcome」のものをコピーしておいてください。
get '/html/(*path)/create' => sub { ... };
get '/html/(*path)' => sub { ... };
なお、このように変化しない共通の部分がある場合は under コマンドを利用すると便利で
す。
under '/html'; # 以下のパスはすべて /html 配下になります。
get '/(*path)/create' => sub { ... };
get '/(*path)' => sub { ... };
また、特にワイルドカード型のプレースホルダを使う場合、条件のゆるいルートを先に書
いてしまうと、後続のパスが無視される結果になることがあります。設定の記載順には注
意してください。
必要なパスの設定が済んだら、コマンドラインから以下のコマンドを実行して、ルートが
正しく設定されているか確認しましょう。期待通りの正規表現が表示されていますか?
perl myapp.pl routes
ルーティングの際に受け取ったパスは、stash、あるいは paramから取り出せます。index
テンプレートに手を入れてどんなパスを受け取ったか確かめてみましょう。
@@ index.html.ep
% layout 'default';
% title 'Welcome';
Welcome to Mojolicious!
<%= stash 'path' %>
Mojolicious::Lite のテンプレートについては、Mojolicious::Lite のドキュメントのほか、
Mojolicious::Guides::Renderingというドキュメントによくまとまっています。基本的には
必要なところに「<%= (Perlの変数、式) %>」を埋め込んでいくだけですが、条件文など、
より複雑な式を書く場合は、行頭を「%」で始めると、その行はそのまま Perl として解釈
されます。また、stash をはじめ、Mojolicious の標準テンプレートにはヘルパーコマンド
がいくつか用意されています。詳しくは Mojolicious::Plugin::DefaultHelpers と、
Mojolicious::Plugin::TagHelpersをそれぞれ確認してみてください。
Mojolicious の テ ン プ レ ー ト に な じ め な い 方 は 、 MojoX::Renderer::TT や
MojoX::Renderer::Xslateといった代替品もありますが、なかには最新版に対応していない
ものもあるかもしれません(TTの最新版はWindowsだとテストに失敗するようです)。
ディスパッチャのテストを書く
ディスパッチャを書いたら、期待通りの動作をしているか、テストしてみましょう。先ほ
どのようにサーバを起動してブラウザで確認してもかまいませんが、Mojolicious に同梱さ
れている Test::Mojo を使うとあたかも人間が実際にアクセスしたかのようなテストコード
を書くこともできます。試しにmyapp.plと同じディレクトリに test.tというテストスクリ
プトを用意してみましょう。
use strict;
use warnings;
use Test::More;
use Test::Mojo;
require 'myapp.pl';
my $t = Test::Mojo->new;
$t->get_ok('/html/foobar')->status_is(200);
done_testing;
ここではまだステータスコードの確認しかしていませんが、Mojo::DOM の機能を使うと
CSS セレクタを利用して HTML の中身を細かく調べることもできます。詳しくは
Test::MojoとMojo::DOMをそれぞれ確認してみてください。
モデルをつくる
モデリングの仕方にもさまざまな流儀がありますが、ここではあまり細かなことは考えず、
モデルの適切なメソッドに「/foo/bar」のようなパス情報(と、必要に応じて更新用のデー
タ)を渡したら、該当するファイルの内容を取り出したり、更新したりできるようになっ
ていればよしとしましょう。
また、テストのしやすさを考えて、表示・更新に使うファイルを格納するディレクトリは
オブジェクト作成時に変更できるようにしておくのが無難です。
本当に小さなアプリケーションで、モデルクラスもそれほど大きくならないことがわかっ
ている場合は、myapp.pl スクリプトと同じディレクトリに MyApp.pm のようなモジュー
ルを用意してもかまいませんが、ここではいずれほかのモジュールも追加することになる
ことが予想できますので、CPAN モジュールで一般的に使われているレイアウトにあわせ
ることにしましょう。lib ディレクトリを掘って、lib/MyApp.pm というファイルを用意し
ます。
package MyApp;
use strict;
use warnings;
use File::Spec;
sub new {
my $class = shift;
bless {@_}, $class;
}
sub home { shift->{home} || '.' }
sub read {
my ($self, $path) = @_;
my $file = File::Spec->catfile($self->home, $path);
open my $fh, '<', $file or die $!;
local $/;
return <$fh>;
}
sub create {
my ($self, $path, $content) = @_;
my $file = File::Spec->catfile($self->home, $path);
open my $fh, '>', $file or die $!;
print $fh $content;
}
1;
モデルをテストする
モデルが書けたらテストもしましょう。CPANのレイアウトにあわせてテストファイルは t
ディレクトリ以下に置くことにします。t/model.tというスクリプトを用意してください。
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use MyApp;
use Test::More;
my $testdir = "$FindBin::Bin/test";
mkdir $testdir unless -d $testdir;
my $m = MyApp->new(home => $testdir);
$m->create('foo', 'foobar');
is $m->read('foo') => 'foobar';
done_testing;
Mojolicious::Liteアプリにモデルを組み込む
最後にMojolicious::Liteアプリからモデルを呼び出せるようにしましょう。
まずはmyapp.plの先頭の方にこのようなコードを追加します。
use lib 'lib';
use MyApp;
my $model = MyApp->new(home => app->home);
app->helper(model => sub {return $model});
これで app->modelからモデルを呼び出せるようになりました。正しくファイルが読み込め
ているか確認しましょう。
get '/(*path)' => sub {
my $self = shift;
my $content = app->model->read($self->param('path'));
$self->stash(content => $content);
$self->render('index');
};
@@ index.html.ep
% layout 'default';
<%= stash 'path' %>
<pre>
<%= stash 'content' %>
</pre>
この変更を加えたことで、先ほど書いたディスパッチャのテストが通らなくなったはずで
す。ファイルが存在している場合、していない場合等々、さまざまな条件を考慮したテス
トを書いてみましょう。また、モデルの設計として、最初はあっさり dieさせておきました
が、本当にこれでよかったでしょうか?
Mojoliciousはデフォルトのままだと utf8が前提になっているため、このままだと、環境に
よっては日本語を含むファイルなどが文字化けします。EncodeやMojo::ByteStreamを利
用して文字コードまわりの対応も強化する必要があるはずです。また、utf8 以外の文字コ
ードを利用するならMojolicious::Plugin::Charsetを組み込む必要もあるでしょう。
今回は時間がたりず、紙の資料はここまでしか用意できていませんが、このセッション内
でも、そのあとでも、わからないことがあったら遠慮なく質問してください。
Happy Hacking!