2009年12月8日:サンプルコードを現在のバージョンで動作するよう修正しました。
Mojoliciousを使ってみよう
前回はすでにできあがったアプリケーションにMojoを組み込んで移植性を高める方法を見ました。今回はこれから新しいアプリケーションを構築する際のベタープラクティスのひとつとして、
まずはひな形から
Mojoliciousのアプリケーションも、
> perl script/mojolicious generate app SimpleWiki > cd simple_wiki
Mojoのひな形に比べていくらか余分にファイルが生成されます。開発用サーバの立ち上げ方はMojoアプリの場合と同じですので、
lib/
package SimpleWiki;
use strict;
use warnings;
use base 'Mojolicious';
# This method will run once at server start
sub startup {
my $self = shift;
# Routes
my $r = $self->routes;
# Default route
$r->route('/:controller/:action/:id')
->to(controller => 'example', action => 'welcome', id => 1);
}
1;
Mojoliciousアプリケーションの処理の流れ
Mojo単独で使う場合はhandlerというメソッドのなかにアプリケーションを入れましたが、
dispatchメソッドのほうは、
startupメソッドでは必要に応じて独自のコンテキストを用意したり、
Merbライクなディスパッチャ
Mojoのルータ
生成されたひな形の例で言うと、
今回はWikiもどきをつくりたいので、
@@ -13,8 +13,8 @@
my $r = $self->routes;
# Default route
- $r->route('/:controller/:action/:id')
- ->to(controller => 'example', action => 'welcome', id => 1);
+ $r->route('/:id/:action')
+ ->to(controller => 'entry', id => 1, action => 'read');
}
1;
モデルをつくる
続いてWikiのデータを扱うモデルをつくります。ここではデータベースは使わず、
package SimpleWiki::Model;
use strict;
use warnings;
use File::Spec::Functions 'catfile';
use base 'Mojo::Base';
__PACKAGE__ ->attr(datadir => 'data');
sub datafile {
my ($self, $id) = @_;
return catfile($self->datadir, $id);
}
sub create {
my ($self, $id, $data) = @_;
open my $fh, '>', $self->datafile($id) or return;
print $fh $data;
return 1;
}
sub read {
my ($self, $id) = @_;
open my $fh, '<', $self->datafile($id) or return;
return do { local $/; <$fh>; };
}
1;
モデルを登録する
モデルができたら、
@@ -4,6 +4,9 @@
use warnings;
use base 'Mojolicious';
+use SimpleWiki::Model;
+
+__PACKAGE__->attr(model => sub { SimpleWiki::Model->new });
# This method will run for each request
sub startup {
@@ -15,6 +18,8 @@
# Default route
$r->route('/:id/:action')
->to(controller => 'entry', id => 1, action => 'read');
+
+ $self->model->datadir($self->home->rel_dir('data'));
}
1;
$self->homeにはアプリケーションのホームディレクトリを指し示すオブジェクトが格納されています
ここで、
コントローラをつくる
さて、
lib/
package SimpleWiki::Entry;
use strict;
use warnings;
use base 'Mojolicious::Controller';
sub create {
my $self = shift;
if (uc $self->req->method eq 'POST') {
$self->app->model->create($self->stash->{id}, $self->req->param('text'));
}
$self->render;
}
sub read {
my $self = shift;
$self->stash->{body} = $self->app->model->read($self->stash->{id});
$self->render;
}
1;
Mojoliciousのコンテキスト
以前は$self->ctxに格納されていたコンテキストは、
テンプレートを用意する
続いて、
ここではデフォルトで生成されるtemplates/
<!doctype html>
<head><title><%= $self->stash->{id} %></title></head>
<body>
<%= $self->stash->{body} %>
</body>
</html>
同様に、
<!doctype html>
<head><title><%= $self->stash->{id} %></title></head>
<body>
<form method="POST">
<textarea name="text"></textarea>
<input type="submit">
</form>
</body>
</html>
リダイレクトの扱い
これで最低限動作するようになりましたので、
lib/
@@ -8,6 +8,7 @@
my $self = shift;
if (uc $self->req->method eq 'POST') {
$self->app->model->create($self->stash->{id}, $self->req->param('text'));
+ $self->redirect_to($self->url_for(action => 'read'));
}
$self->render;
}
@@ -15,6 +16,7 @@
sub read {
my $self = shift;
$self->stash->{body} = $self->app->model->read($self->stash->{id});
+ return $self->redirect_to($self->url_for(action => 'create')) unless defined $self->stash->{body};
$self->render;
}
Catalystをご存知の方は$self->url_
Mojoliciousのログ
Mojoliciousを含むMojoアプリケーションにはログ機能がついています。動作確認したあとでlogディレクトリの下を見るとdevelopment.
@@ -22,4 +22,14 @@
$self->model->datadir($self->home->rel_dir('data'));
}
+sub development_mode {
+ my $self = shift;
+ $self->log->handle(*STDERR);
+}
+
+sub production_mode {
+ my $self = shift;
+ $self->log->level('error');
+}
+
1;
コントローラ内部からログを出力したい場合は、
@@ -8,6 +8,7 @@
my $self = shift;
if (uc $self->req->method eq 'POST') {
$self->app->model->create($self->stash->{id}, $self->req->param('text'));
+ $self->app->log->info('created '.$self->stash->{id});
$self->redirect_to($self->url_for(action => 'read'));
}
$self->render;
Test::Mojoを使ったテスト
最後にMojoliciousアプリケーションのテストについても触れておきましょう。
Mojoliciousアプリケーションのテストは基本的に前回見たMojoアプリケーションのテストと同じで、
@@ -3,12 +3,17 @@
use strict;
use warnings;
-use Test::More tests => 5;
+use Test::More tests => 7;
use Test::Mojo;
use_ok('SimpleWiki');
# Test
my $t = Test::Mojo->new(app => 'SimpleWiki');
-$t->get_ok('/')->status_is(200)->content_type_is(Server => 'text/html')
- ->content_like(qr/Mojolicious Web Framework/i);
+$t->post_form_ok('/test/create' => {text => 'test is ok'})
+ ->status_is(302);
+
+$t->get_ok('/test')
+ ->status_is(200)
+ ->content_type_is('text/html')
+ ->content_like(qr/test is ok/);
Mojoliciousはあくまでサンプルにすぎません
さて、
次回はMojoが誕生した経緯を振り返りながら、