Perl Hackers Hub

第18回 Amon2によるWebアプリケーションの高速開発(2)

この記事を読むのに必要な時間:およそ 2 分

前回の(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のディレクトリ構造

図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の起動画面

図2 Amon2の起動画面

設定ファイル

デフォルトでは設定ファイルは.plファイル,つまりPerlそのもので書くことになっています。YAMLYAML 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は,CLICommand Line Interfaceなどのときに使うためのコンテキストオブジェクトで,ここにプロジェクトのベースディレクトリを取得するための$c->base_dir()を追加したり,データベースハンドルを取り出すための$c->dbh()メソッドを追加することができます。

一方,MyApp::Webは,Webアプリケーション用に特化したコンテキストオブジェクトです図3)⁠ここにはリクエストオブジェクトを取り出すための$c->req()メソッド,テンプレートエンジンを用いてレンダリングするための$c->render()メソッドなどがMyApp.pmのメソッドに加えて使えるようになっています。

図3 Amon2のコンポーネント

図3 Amon2のコンポーネント

コンテキストの継承関係は図4のようになっています。ちょっと変則的ですが,こうすることにより使いやすくなっています。

コンテキストオブジェクトはAmon2アプリケーションが実行されている間はAmon2->context()というメソッドを呼ぶことで取り出すことができます。

図4 Amon2の継承関係

図4 Amon2の継承関係

Web以外でのコンテキスト

CLIやジョブキューのワーカなどを作る場合には,コンテキストオブジェクトを明示的に設定する必要があります。

use MyApp;
my $app = MyApp->bootstrap();

こうすることで,グローバル変数にコンテキストオブジェクトが設定され,いつでも参照できるようになるのです。このしくみは,Plaggerと,SledgeのSledge::Registrarからアイデアを拝借しています。具体的には$Amon2::CONTEXTという変数に設定されます。

注2)
大規模なアプリケーションの場合には,MyApp::Admin,MyApp::Web,MyApp::Readerなどのように,複数のコンテキストオブジェクトを定義します。

コントローラ

生成されたコントローラのコードを見てみましょうリスト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)こちらです。>

著者プロフィール

tokuhirom(とくながひろむ)

サブテク所属

生き馬の目をぬく東京で育ち,Perl5 を中心としたウェブ開発を主におこなっている。詳細は以下のとおり。

http://github.com/tokuhirom/

コメント

コメントの記入