前回の(1)はこちら から。
Amon2のインストール
Amon2はCPANモジュールですから、cpanmコマンドで簡単にインストールできます。コマンドラインで次のように入力すればすんなりとインストールされます。
% curl -L http://cpanmin.us | perl - Task::Amon2 -nv
Amon2を使ってみる
Amon2のインストールが済むと、amon2-setup.plというコマンドが使えるようになっています。これを使うとAmon2のスケルトンが作れます。
% amon2-setup.pl --flavor=Basic MyApp
上記のようにコマンドラインで入力すると、MyAppディレクトリ以下にスケルトンができあがります。生成されるディレクトリ構造は図1 のようになります。jsディレクトリに配置されるJavaScriptファイルの多さと、t、xtディレクトリに配置されるサンプルテストスクリプトの多さが特徴です。
図1 Amon2のディレクトリ構造
テストスクリプトは、Test::WWW::Mechanize::PSGI を利用したものや、jshint を利用してJavaScriptの文法チェックをするものなど、いくつかの基本的なテストケースを用意しています。これらを手本に利用者は自分のアプリケーションに合ったテストケースへと成長させていくことができるようになっています。
起動してみる
できあがったスケルトンはすぐに試してみることができます。次のように実行するとアプリケーションサーバが起動します。
% plackup app.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/
ブラウザでhttp://127.0.0.1:5000/にアクセスし、図2 のような画面が現れたら成功です。
図2 Amon2の起動画面
設定ファイル
デフォルトでは設定ファイルは.plファイル、つまりPerlそのもので書くことになっています。YAML(YAML Ain't Markup Language )などを使うこともできますが、YAMLでアプリケーションの設定を書こうとすると、YAML内DSLのようなものを再発明する羽目になったりしがちですから、素直に.plファイルを使うのがお勧めなのです[1] 。
最新版では、デフォルトの設定ファイルはリスト1 のようになっています。
リスト1 デフォルトの設定ファイル
use File::Spec;
use File::Basename qw(dirname);
my $basedir = File::Spec->catdir(dirname(__FILE__), '..');
$basedir = File::Spec->rel2abs($basedir);
my $dbpath = File::Spec->catfile(
$basedir, 'db', 'development.db'
);
+{
'DBI' => [
"dbi:SQLite:dbname=$dbpath", '', '',
+{
sqlite_unicode => 1,
}
],
};
[1] Catalyst::Plugin::ConfigLoaderではENV(foo)のような特殊な記法が自動的に置換される機能が実装されていますが、筆者はそうするぐらいなら.plで書いたほうがよいように思います。
コンテキスト
Amon2の世界では、コンテキストというものの存在が非常に重要です。コンテキストを理解すればAmon2の80%を理解したと言ってもよいでしょう。コンテキストとは日本語で言うと文脈です。Amon2ではデフォルトで、MyApp.pm、MyApp::Webという2種類のコンテキストクラスが用意されます[2] 。
MyApp.pmは、CLI(Command Line Interface )などのときに使うためのコンテキストオブジェクトで、ここにプロジェクトのベースディレクトリを取得するための$c->base_dir()
を追加したり、データベースハンドルを取り出すための$c->dbh()
メソッドを追加することができます。
一方、MyApp::Webは、Webアプリケーション用に特化したコンテキストオブジェクトです(図3 ) 。ここにはリクエストオブジェクトを取り出すための$c->req()メソッド、テンプレートエンジンを用いてレンダリングするための$c->render()
メソッドなどがMyApp.pmのメソッドに加えて使えるようになっています。
図3 Amon2のコンポーネント
コンテキストの継承関係は図4 のようになっています。ちょっと変則的ですが、こうすることにより使いやすくなっています。
コンテキストオブジェクトはAmon2アプリケーションが実行されている間はAmon2->context()
というメソッドを呼ぶことで取り出すことができます。
図4 Amon2の継承関係
Web以外でのコンテキスト
CLIやジョブキューのワーカなどを作る場合には、コンテキストオブジェクトを明示的に設定する必要があります。
use MyApp;
my $app = MyApp->bootstrap();
こうすることで、グローバル変数にコンテキストオブジェクトが設定され、いつでも参照できるようになるのです。このしくみは、Plagger と、SledgeのSledge::Registrarからアイデアを拝借しています。具体的には$Amon2::CONTEXTという変数に設定されます。
コントローラ
生成されたコントローラのコードを見てみましょう(リスト2 ) 。シンプルなコードですね。RubyのSinatra的に書けます。より複雑なコードになる場合には、ルーティングルールを中央にまとめて、コントローラを複数用意することもできます。$cは前述のコンテキストオブジェクトです。具体的にはMyApp::Webのインスタンスですね。
リスト2 生成されたディスパッチャ
package MyApp::Web::Dispatcher;
use strict;
use warnings;
use utf8;
use Amon2::Web::Dispatcher::Lite;
any '/' => sub {
my ($c) = @_;
return $c->render('index.tt');
};
post '/account/logout' => sub {
my ($c) = @_;
$c->session->expire();
return $c->redirect('/');
};
1;
各コードは、戻り値としてレスポンスオブジェクトを返します。レスポンスオブジェクトを$cの中に埋めてしまうフレームワークが多い中で、このAmon2のアプローチは割にめずらしいものです。しかし、このようにリクエストを受け取ってレスポンスオブジェクトを返すという一連の処理をストレートに表現することにより、初心者にもわかりやすいようになっているのです。
<続きの(3)はこちら です。>