typester さんが
NEXT やめやめ。
なんもうれしいことない。
plagger の hook 機構をぱくろう。そうしよう。
from: CLON - 2006/05/04 - Plugin
とおっしゃっていたので、plagger の hook 機構を catlxom に組み込むとどんな感じになるのかなー、といきなりコードを書こうとしたら混乱してきたので、catlxom の動作の流れを、特にプラグイン機構に注目して整理してみることにした。
まずは以下の2箇所のコードで、Catlxom の基底クラスを @Catlxom::ISA につっこむ。
use Catalyst qw( ConfigLoader Flavour );
__PACKAGE__->setup( do { my @plugin = qw/+Catlxom::Base/; push @plugin, 'Static::Simple' if ( $ENV{CATALYST_ENGINE} || '' ) =~ /^HTTP/; push @plugin, 'DebugScreen' if $ENV{CATALYST_DEBUG}; @plugin; } );
これで @Catlxom::ISA は以下の様な感じになる。
@Catlxom::ISA = qw( Catlxom::Base Catalyst::Plugin::Static::Simple Catalyst::Plugin::ConfigLoader Catalyst::Plugin::Flavour Catalyst Catalyst::Controller );
catlxom 固有なのは、Catlxom::Base があるところ。
Catlxom::Base::setup が実行される。実際のコードは以下の通り。
sub setup { my $class = shift; $class->NEXT::setup(@_); $class->catlxom->setup($class); }
$class->catlxom は、Class::Data::Inheritable を使ってこんな感じで定義されてる。
__PACKAGE__->mk_classdata( catlxom => Catlxom::Context->new );
というわけでこの setup では、 Catlxom::Context の setup メソッドが実行される。
Catlxom::Context は Catlxom::Context::Base を基底クラスとしていて、setup メソッドもこの基底クラスにある。こんな感じ。
sub setup { my ($self, $c) = @_; $self->plugin->load($c); { # plugin setup no warnings 'redefine'; local *setup = sub { }; $self->setup($c); } }
$self->plugin は Calss::Data::Inheritable でこんな風に定義されてる。
__PACKAGE__->mk_classdata( plugin => Catlxom::Plugins->new );
なのでこの setup メソッド中の $self->plugin->load($c) では、Catlxom::Plugins の load メソッドが実行される。このメソッドでは、@Catlxom::Context::ISA に catlxom プラグインクラスを基底クラスとしてつっこむ。@Catlxom::Context::ISA はこんな感じになる。
@Catlxom::Context::ISA = qw( Catlxom::Plugin::Entry::Blosxom Catlxom::Plugin::Filter::Path Catlxom::Plugin::Filter::Date Catlxom::Plugin::Format::Textile Catlxom::Plugin::Paginate::Simple Catlxom::Plugin::Template::TT Catlxom::Context::Base );
更におなじく setup メソッド中の
# plugin setup no warnings 'redefine'; local *setup = sub { }; $self->setup($c);
で、Catlxom::Context の基底クラス中の setup メソッドを NEXT で順に実行していく。つまり、各プラグインの setup メソッドを順次実行する。
ちなみに、各プラグインメソッド中の $self は Catlxom::Context クラスのインスタンスであって、各プラグインクラスのインスタンスではないので注意。$c は Catlxom クラス。
これで起動時のプラグインロード、セットアップが完了。
ブラウザからアクセスすると Catlxom::default が実行される。実際のコードはこんな感じ。
sub default : Private { shift->catlxom->dispatch(shift); }
これで Catlxom::Context::dispatch が実行される。
Catlxom::Context::dispatch の実体は Catlxom::Context::Base::dispatch であり、以下の様なコードになっている。
sub dispatch { my ( $self, $c ) = @_; $self->initialize($c); $self->start($c); $self->update($c); $self->entries->filter($c); $self->sort($c); $self->paginate($c); $self->fixedup($c); $self->interpolate($c); $self->end($c); }
これにより Catlxom::Context の基底クラス、つまり 各 catlxom プラグインの initialize, start などが NEXT で順次実行されていく。