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 で順次実行されていく。