|tcsh| $ catalyst.pl myapp ||< で、作成された myapp.pm をまず見てみます。
|perl| use Catalyst::Runtime 5.80; use parent qw/Catalyst/; use Catalyst qw/-Debug ConfigLoader Static::Simple/;
PACKAGE->config( name => 'myapp' ); PACKAGE->setup(); ||< Catalyst::Runtime はソースを読む限り空実装のようなので、無視しよう。そうなると、myapp は Catalyst を継承しているとともに、Catalyst をロードしてる。ということで、見ていく順番としては、 +Catalyst::import +Catalyst::config +Catalyst::setup となる。
**Catalyst::import
|perl| sub import { my ( $class, @arguments ) = @_;
my $caller = caller();
return if $caller eq 'main';
my $meta = Moose::Meta::Class->initialize($caller);
unless ( $caller->isa('Catalyst') ) {
my @superclasses = ($meta->superclasses, $class, 'Catalyst::Controller');
$meta->superclasses(@superclasses);
}
# Avoid possible C3 issues if 'Moose::Object' is already on RHS of MyApp
$meta->superclasses(grep { $_ ne 'Moose::Object' } $meta->superclasses);
unless( $meta->has_method('meta') ){
$meta->add_method(meta => sub { Moose::Meta::Class->initialize("${caller}") } );
}
$caller->arguments( [@arguments] );
$caller->setup_home;
} ||< $caller は myapp であり、先に見たように Catalyst を継承しているので unless ブロックには入りません。 結果、 ++Catalyst::arguments ++Catalyst::setup_home が呼び出されます。ただし、Catalyst::arguments は単なる setter なので、ここでは省略して、Catalyst::setup_home を見ます。
|perl| sub setup_home { my ( $class, $home ) = @_;
if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
$home = $env;
}
$home ||= Catalyst::Utils::home($class);
if ($home) {
#I remember recently being scolded for assigning config values like this
$class->config->{home} ||= $home;
$class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
}
} ||< このメソッドはアプリケーションのホームディレクトリ取得メソッドです。Catalyst::Utils::env_value は CATALYST_xx とか MYAPP_xx とかの環境変数から情報を取得しようとします。この場合だと CATALYST_HOME とかですね。それが見つからない場合は、Catalyst::Utils::home が呼ばれ、この中ではいろいろ泥臭いことをやってます。 めでたくホームディレクトリが見つかると、それを config ハッシュに格納します。
ちなみにこの config ハッシュは、Catalyst の親クラスである Catalyst::Component の中で定義されています。混乱しそうですが、今のところのクラス階層は +Catalyst::Component +Catalyst +myapp という形なのですね。
結局、import が呼ばれた段階で、アプリケーションのホームディレクトリが設定されるんだ、ということでしょうか。
**Catalyst::config
|perl| PACKAGE->config( name => 'myapp' ); ||< これは前述の Catalyst::Component::config を呼んで、アプリケーション名を config ハッシュに追加しているだけなので省略。
**Catalyst::setup
|perl| sub setup { my ( $class, @arguments ) = @_; croak('Running setup more than once') if ( $class->setup_finished );
unless ( $class->isa('Catalyst') ) {
Catalyst::Exception->throw(
message => qq/'$class' does not inherit from Catalyst/ );
}
if ( $class->arguments ) {
@arguments = ( @arguments, @{ $class->arguments } );
}
# Process options
my $flags = {};
||< arguments を呼び出していますが、これは import のときにセットしたものに対する getter として呼ばれています。 import のときに set されたのは '-Debug', 'ConfigLoader', 'Static::Simple' の 3 つなので、これが @arguments にセットされた状態になってるはずです。
|perl| foreach (@arguments) {
if (/^-Debug$/) {
$flags->{log} =
( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
}
elsif (/^-(\w+)=?(.*)$/) {
$flags->{ lc $1 } = $2;
}
else {
push @{ $flags->{plugins} }, $_;
}
}
||< この for ループで @arguments の内容が plugins としてセットされてますね。また、arguments で "log=info" などとしておけば良いこともわかります。
|perl| $class->setup_home( delete $flags->{home} );
$class->setup_log( delete $flags->{log} );
$class->setup_plugins( delete $flags->{plugins} );
$class->setup_dispatcher( delete $flags->{dispatcher} );
$class->setup_engine( delete $flags->{engine} );
$class->setup_stats( delete $flags->{stats} );
||< 大量の setup_xxx メソッドがある。setup_home はもう見たので省略。
***Catalyst::setup_log
|perl| sub setup_log { my ( $class, $levels ) = @_;
$levels ||= '';
$levels =~ s/^\s+//;
$levels =~ s/\s+$//;
my %levels = map { $_ => 1 } split /\s*,\s*/, $levels;
my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
if ( defined $env_debug ) {
$levels{debug} = 1 if $env_debug; # Ugly!
delete($levels{debug}) unless $env_debug;
}
unless ( $class->log ) {
$class->log( Catalyst::Log->new(keys %levels) );
}
if ( $levels{debug} ) {
Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
$class->log->debug('Debug messages enabled');
}
} ||< まだ log オブジェクトが設定されていない場合は、Catalyst::Log をコンストラクトして設定しておく、くらいでしょうか。 また、debug レベルの場合は、myapp に対して常に true を返す debug メソッドを生やしています。
***Catalyst::setup_plugins 次は plugin をロードする setup_plugins。
|perl| sub setup_plugins { my ( $class, $plugins ) = @_;
$class->_plugins( {} ) unless $class->_plugins;
$plugins ||= [];
my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins);
for my $plugin ( reverse @plugins ) {
Class::MOP::load_class($plugin);
my $meta = find_meta($plugin);
next if $meta && $meta->isa('Moose::Meta::Role');
$class->_register_plugin($plugin);
}
my @roles =
map { $_->name }
grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') }
map { find_meta($_) }
@plugins;
Moose::Util::apply_all_roles(
$class => @roles
) if @roles;
}
||<
Catalyst::Utils::resolve_namespace は、plugin 名の接頭語に「+」とか「~」とか付けない限りは特に気にせず、Catalyst::Plugin:: が plugin 名の最初に付くものと覚えておけば良い。そうやってフルパッケージ名を解決したところで、そのプラグインをロードする。プラグインが Role の場合は、それを適用する。 だいたい他のもそんなかんじ。
次は setup_components ですが、長そうなので一旦ここで切る。