理系学生日記

おまえはいつまで学生気分なのか

Catalyst ソースリーディング2

**setup_components

Catalyst::setup から呼び出される setup_components は、その名前の通り、Catalyst のコンポーネントのロードを行う。

|perl| sub setup_components { my $class = shift;

my $config  = $class->config->{ setup_components };

my @comps = sort { length $a <=> length $b }
            $class->locate_components($config);

||< 実際のロードは、setup_components から呼び出される locate_components によって行われる。このメソッドでは、Module::Pluggable::Object を用いて、MyApp 配下にある Controller、Model、View 用のクラスを全てロードする(Module::Pluggable::Object にはオプションを渡せるようになっているので、実際にはロードするモジュールをフィルタリングすることも可能)。

この @comp に対して複雑な処理をした後で、for 文を実行。この for 文では、まず setup_components を呼んでいるので、その定義を見てみる。

|perl| for my $component (@comps) { my $instance = $class->components->{ $component } = $class->setup_component($component); my @expanded_components = $instance->can('expand_modules') ? $instance->expand_modules( $component, $config ) : $class->expand_component_module( $component, $config ); for my $component (@expanded_components) { next if $comps{$component}; $class->_controller_init_base_classes($component); # Also cover inner packages $class->components->{ $component } = $class->setup_component($component); } } ||<

**setup_component

|perl| sub setup_component { my( $class, $component ) = @_;

unless ( $component->can( 'COMPONENT' ) ) {
    return $component;
}

||<

まず、COMPONENT メソッドを持っていないコンポーネントは門前払いされる。COMPONENT メソッドは、Catalyst::Component で定義されており、その Component をインスタンス化 (new を呼び出す) する役割を果たす。 実際に COMPONENT メソッドが呼び出されるのはこの直後である。

|perl| my $suffix = Catalyst::Utils::class2classsuffix( $component ); my $config = $class->config->{ $suffix } || {}; local $config->{catalyst_component_name} = $component;

my $instance = eval { $component->COMPONENT( $class, $config ); };

||< Catalyst::Utils::class2classsuffix は、"MyApp::Controller::Foo::Bar" を "Controller::Foo::Bar" に、"MyApp::View::Hoge" を "View::Hoge" にする役割を果たす。この後、config ハッシュから、その正規化(?)した名前をキーにして、COMPONENT メソッドへの引数となるコンフィグを取得し、実際にインスタンス化を行う。ここでエラーがあれば、例外(Catalyst::Exception) が発生する。

エラーがなければ、インスタンス化に成功したインスタンスを返却する。

**expand_modules

expand_modules は、インスタンス化したモジュールの内部モジュールを返す(この処理を行うために、内部で Devel::InnerPackage を使っている)。返却された内部モジュールに対して、再び setup_component が呼び出される仕掛け。これによって、コンポーネントがロードされていく。