Controllerなどの機能拡張をMooseのRoleで行う - その1

http://dann.g.hatena.ne.jp/dann/20080605/p5

で書いていたものですが、ここに書いていたアイデアの実装を用意してみました。
Controllerのpluginという形で実現するために、moose branchのcatalystにパッチをあてています。setup_actionsの後でRoleをconsumeしないと都合がわるいので、本体にパッチをあてています。

***************
*** 932,940 ****
--- 932,951 ----
      }
      $class->log->_flush() if $class->log->can('_flush');
  
+     $class->setup_component_pluigns;
      $class->setup_finished(1);
  }
  
+ sub setup_component_pluigns {
+     my $class = shift;
+     foreach my $component ( keys %{ $class->components } ) {
+         my $component_instance = $class->components->{$component};
+         if ( $component_instance->can('load_plugins') ) {
+             $component_instance->load_plugins;
+         }
+     }
+ }
+ 
  =head2 $c->uri_for( $path, @args?, \%query_values? )

以下がBaseのController。

今は実験でベースのControllerでやってるけれど、多分、pluginをロードするところとかは、Catalyst::Componentレベルでするのがいいんだろうなぁと。Component用のPluginのような概念を導入したいなぁと。

package MyApp::BaseController;
use Moose;
BEGIN {
    extends 'Catalyst::Controller';
}

# 多分ここらはCatalyst::Componentに移動させるのがよい
with 'MooseX::Object::Pluggable';
has '+_plugin_app_ns' => (default => sub {['MyApp::Controller']});

sub load_plugins {
    my $self = shift;
    $self->load_plugin($_) for qw(Example);
}

sub index : Path Args(0) {
    my ( $self, $c ) = @_; 

    # Hello World
    $c->response->body( $c->welcome_message );
}

sub default : Path {
    my ( $self, $c ) = @_; 
    $c->response->body( 'Page not found' );
    $c->response->status(404);
    
}

1;

以下、Controller

package MyApp::Controller::Example;
use Moose;
BEGIN {
    extends 'MyApp::BaseController';
}

sub hoge : Local {
    my ($self, $c) =@_;
    $self->hello;
}

1;

Controller用Plugin

package MyApp::Controller::Plugin::Example;
use Moose::Role;

sub hello {
    my ($self, $c) = @_; 
    warn 'hello';
}

1;

TODO

  • Catalyst::Componentレベルにpluginをロードする仕組みをもっていった場合の仕様決め
  • メソッドバッティング時のaliasの仕様検討
  • Component初期化時に、config読んだりとかっていうのを多分したいので、どこにhookさせるかの検討。Componentの既存メソッドにフックさせるか、新しくplugin用にhookさせるメソッドを用意させるかどっちか。