読者です 読者をやめる 読者になる 読者になる

理系学生日記

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

忍者TOOLS

Catalyst ソースリーディング2

setup_components

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

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 を呼んでいるので、その定義を見てみる。

    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

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

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

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

    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 が呼び出される仕掛け。これによって、コンポーネントがロードされていく。