読者です 読者をやめる 読者になる 読者になる

北海道苫小牧市出身の壮年PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

Amon2のソースを読む(3)

perl+web

今日はAmon2-2.49のscaffoldとDispatcher。--flavor=Basic が基本なんで、それを読む。

概要

scaffold 内のPerl関連のファイルはapp.psgiとYourProject.pmとYourProject::Webと YourProject::Web::Dispatcher だけ。実際のユーザ側の処理は YourProject::Web::Dispatcher がディスパッチした先に書くことになるので、Dispatcher.pm に直接書くか、YourProject::Web::C 以下のクラスに書くことになる。


YourProject::Web::Dispatcher を書くために Amon2::Web::Dispatcher::Lite と Amon2::Web::Dispatcher::RouterSimple が提供されているので、これも一緒に見る。


なお、 YourProject::Web::Dispatcher を使う気がないなら、Amon2::Web->dispatch に直接処理を書くこともできる。そうすると、--flavor=Minimumの構成となる。

app.psgi

YourProject/app.psgi では、robot.txtとfavicon.icoと/static/ をPlack::Middleware::Static へ渡して静的に処理させている。また、Plack::Middleware::ReverseProxy が入っていることからリバースプロクシの裏での動作を前提としていることがわかる。必要に応じてenable_if でReverseProxyを有効にするアクセス元のホストを指定するように変更するのもよいだろう。

YourProject.pm

YourProject クラスはAmon2 クラスを継承したコンテキスト。WEBに特化しない処理はここに書くとよい。例えば、DBIプラグインのロードとか。

YourProject::Web

YourProject::Web ではYourProject クラスを継承してコンテキストとして振る舞うとともに、Amon2::Web をMixinとして取り込んでWebの機能を提供する。このクラスの最も重要な仕事は Amon2::Web が要求するdispatch と create_view を実装すること。create_view は初期化したXslate を返すように実装されており、テンプレから c という変数でカレントコンテキストにアクセスできるようにしている。他、テンプレへはuri_with とuri_for のショートカットも提供。dispatch メソッドの実装はYourProject::Web::Dispatcher->dispatch に投げるだけになっている。


YourProject::Webにはその他に、YourProject::Web::C:: にあるコントローラを全部ロードしたり、プラグインを読み込むコード、フックの定義などが含まれる(が、デフォルトのscaffoldだとAmon2::Web::Dispatcher::Lite を使ってるので、C::以下のクラスを定義する必要はないように思える)。

YourProject::Web::Dispatcher

デフォルトではAmon2::Web::Dispatcher::Lite を使ってディスパッチするコードが書かれている。eg/ ディレクトリには Amon2::Web::Dispatcher::RouterSimple を使った例が入っている。::Liteも::RouterSimple も定義したルーティングに対して __CLASS__->dispatch($c) というコンテキスト$cを受け取るメソッドを作ってくれるので、scaffoldでYourProject::Web 内に生成されるコードと相性がいい(そういう風にscaffoldが作られてるのだから当たり前だけど)。

Amon2::Web::Dispatcher::Lite

use Router::Simple::Sinatraish するのと同じになるよう、import 関数内で Sinatraish->export_to_level(1) で関数類をエクスポートしている。追加でコンテキスト$cとルーティング情報を結びつける糊のコードとして、前述のdispatch メソッドを定義している。この糊は、 $envに対してmatchを実行して、選択された処理を$cとマッチング結果を引数として呼び出す。URL内にパターンを指定したなら、この第二引数のマッチング結果から参照できる。

Amon2::Web::Dispatcher::RouterSimple

このコミットの辺りからこのクラスは表立っては使われなくなったので、あまり推奨しない方向に進んでるのかもしれないけど一応読む。


Router::Simple をDSL的に使えるよう、connect、submapper、match、as_stringを関数としてエクスポートしている。これらの処理の主役となるインスタンスはrouter関数で取得できる。connectはRouter::Simpleのものより少し拡張されていて、"コントローラ名#アクション名"という指定もできる。この指定の場合の \%destination は、{controller => コントローラ名, action => アクション名}と解釈される。


dispatch がコンテキスト$cとマッピングを結ぶ糊で、"コンテキストクラス名::C::コントローラ名"というクラスのアクション名のメソッドを呼ぶ。コンテキストクラスの名前は、通常はYourProject::Web となるはず。PODにも書いてあるが、コントローラ名とアクション名はmatch()結果のcontrollerとactionを使うので、パターンに:matchや:controllerを書いておくとURLを元に自由に指定させられる(使いどころは少ない気がするけど)。


ディスパッチされたメソッドには、Liteの時と同じようにコンテキスト$cとmatch()の結果が渡されるので、これを使って処理を書く。