[僕] 最近の Catalyst の構成

僕ト云フ事

たろマークはてなブックマーク

2009年06月15日

[catalyst][perl] 最近の Catalyst の構成

最近 Catalyst のエントリをよく見かけるので自分の構成をさらしてみます。コードは CodeRepos にあります。

share - Revision 30441: /lang/perl/Chaostr/trunk

元々は、作ろうとしたアプリがあったんですが、去年の Catalyst confernce 以降、MyApp 的実験場になってます。仕事で作ったものはさらせないので、構成だけ表に出す感じ。ちなみに今のところ Catalyst 5.7 系でしか使ってないです。

あと、Controller クラスのベースで Resources を使ってるけど、自分のやり方は推奨されない使い方をしてます。新規投稿や編集画面用の URL を作るために一度自前 Base クラスを噛ませてたんですが、new, edit はデフォールトであります。Resources の使い方とかはこっちに書きました。

クラス構成

現在の構成をざっと図にするとこんな感じです。

chaostr.png

Config, Log, DB, Validator を Catalyst から切り離して Service(Logic) クラスでも直接扱えるようにしてます。

PseudoRequest については後述。

Chaostr::Class / Chaostr::Role

このあたりは、Angelos インスパイアです。と言うか最初はまるパクリだったw
Angelos::Class は Mouse ですが、Chaostr::Class は Any::Moose で、呼び出し元が Moose だったら、Moose、そうでなければ Mouse になります。Cat 5.8 系で Moose になってもいいようにと。test やコマンドラインからは Mouse がいいなぁと言う感じで。

Chaostr::Class::* は Service クラスで mixin して使用するクラスです。
config, log, db, validator とかも mixin されてます。mixin はこんなやり方でいいのかがちょっとわからない。

Chaostr::Config

tomyhero さんが書いてる CatalystとConfig - perl-mongers.org を見てもらうとわかると思います。

Config::Multi を singleton 化して、どこでも使えるようにしてるよ!
すこし違うのは __path_to()__ とか __uri()__ とかで Path::Class や URI オブジェクトになる点くらい。

Chaostr::Log

Log::Dispatch::Config 使ってます。
extlib に Log::Dispatch::Configurator::Hash というのをこさえてあって、hash から Log::Dispatch::Config::Configurator オブジェクトを作れるようにしてます。

開発中は Log::Dispatch::Colorful を使ってます。Log::Coloful は、Log::Dispatch のメソッドいじったりしてるので、Dumper が必要ない人は yappo さん作の Log::Dispatch::Color 使うといいよ。

$Log::Dispatch::Config::CallerDepth で呼び出し元からの深さを指定してるんだけど、Service から呼んだときと、Catalyst から呼んだときでエラー元の表示が変わってしまってるのが少し悩み。

Validator

FormValidator::LazyWay 使ってます。validator は Catalyst にあればいいかと思ってたんですが、Service クラスに Request を渡しているので Service クラスで validate できても良いなぁと思って切り離してます。

どっちでもできるようにしておいて、なるべく Service 側でできるようにという感じ。

DB

DBIx::Class です。これも Catalyst::Model::Schema::DBIC とかは使わずに自前 Singleton 化して Service クラスでも呼び出せるようにしてます。

Model

Catalyst::Model::MultiAdaptor を使用して、Service クラスが読み込まれる用にしています。
MultiAdaptor は、いくつかの LifeCycle をサポートしてますが、LifeCycle::Singleton に手を入れた LifeCycle::SingletonPerRequest っていうのを作って使ってます。

これは起動時に指定したクラスを require して instance 化するまでは同じですが、その instance 内でリクエスト毎に $c->request と $c->session が Service クラス側のアクセッサに渡ってくるようになってます。

sub install {
    my $self = shift;
    my $instance = $self->create_instance( $self->adapted_class, $self->config );
    Sub::Install::install_sub(
	{   code => sub {
		my ( $component, $context ) = @_;
		$instance->request($context->req);
		$instance->session($context->session);
 
		return $instance;
            },
            into => $self->model_class_name,
            as   => 'ACCEPT_CONTEXT',
	}
    );
}

もうね、Model として切り分けたときに request とか session をいちいち渡すのが面倒になって、「自動で全部渡してしまえ」と思った末の結果です。あとは、メソッド側で使いたいのだけ使えよと。

引数として必要な分だけ渡すと言う作りもできるよ。

後は、FormValidator::LazyWay を validator として使ってます。
validate は Catalyst 側でやればいいと思うんですが、作ってて Service 側でもやりたくなったら使おうくらいの考えで搭載しました。

CLI と test

Model のところ読んで、結局 Catalyst 依存してるじゃんかと思われるかもしれませんが、hash を渡すと request オブジェクトに変えてくれる PseudoRequest というクラスをこさえて、CLI や test も Service クラスを使えるようにしてます。

PseudoRequest にファイルの場所とか教えると $self->request->upload 的なこともできるので、ファイルアップロードのテストまで書けるようにはしたつもり。

参考

参考にしたというか、大元は avmaster さんのAV女優ブログ検索のソースで、この一年ぐらいちまちま育ててた感じです。

blog comments powered by Disqus