Class::Component その2
※ 例文中の個人名などは架空のものです。
やりたいこと
- 人によって自転車の色は異なる。色の情報は外部のデータファイルとかDBとかにある。色の情報は最初に調べておいて、聞かれたらすぐに答えられるようにしておきたい。
- やれることは全部やりたい。
やったこと
妥当かどうかわからないすけどやったこと。
- Pluginが呼ばれる前に外部データを読むとかの初期化処理をしたい。でもってその初期化処理は、Pluginされたエッジクラスに応じて変化させたい。
- エッジクラス (NaoyaとかKanjiManとか) で、config に { injected => __PACKAGE__ } を詰める。
- __PACKAGE__->class_component_reinitialize(config => $config); でセットする。
- __PACKAGE__->class_component_reinitialize と use Class::Component config => {...} は等価。らしい→ http://tech.yappo.jp/docs/soozycon2/の38ページ
- Plugin (Jitensyaとか) は、newの中で$self->initが呼ばれる。なのでここで初期化処理をやる。
- Pluginでは $self->config->{injected} でエッジクラスで詰めたデータがとれる。
- initでもこれを参照して、この値に応じて初期化処理を変えたりなんかしちゃう。
- エッジクラス (NaoyaとかKanjiManとか) で、config に { injected => __PACKAGE__ } を詰める。
- Pluginされたメソッドを全部呼びたい。
- Naoya->new->allで、injectされたPluginのMethodを全部呼ぶようにする。
- NaoyaのスーパークラスのHStaffでall関数を定義。
- $self->class_component_methods で、injectされたMethod名をキーとしてもつハッシュが返ってくる。
- ループでぐるんぐるん回して全部実行する。
- Naoya->new->allで、injectされたPluginのMethodを全部呼ぶようにする。
$ ./hatena.pl blue ring ring by Naoya --- no color watami DE nonderu. chin chin by KanjiMan
コードは↓で。
#!/usr/bin/env perl use strict; use warnings; use Naoya; Naoya->new->all; print "---\n"; use KanjiMan; KanjiMan->new->all;
package HStaff; use strict; use warnings; use Class::Component; __PACKAGE__->load_components( qw/ Autocall::InjectMethod / ); sub all { my($self, $context, @args) = @_; for my $method (keys %{ $self->class_component_methods }) { $self->$method(@args); } } 1;
package Naoya; use strict; use warnings; use base 'HStaff'; use Class::Component; my @PLUGINS = qw(Jitensya); my $config = { map { $_ => { injected => __PACKAGE__ } } @PLUGINS }; $config->{Jitensya}{sound} = 'ring ring'; __PACKAGE__->load_plugins( @PLUGINS ); __PACKAGE__->class_component_reinitialize(config => $config); 1;
package KanjiMan; use strict; use warnings; use base 'HStaff'; use Class::Component; my @PLUGINS = qw(Jitensya Nijikai); my $config = { map { $_ => { injected => __PACKAGE__ } } @PLUGINS }; $config->{Jitensya}{sound} = 'chin chin'; $config->{Nijikai}{where} = 'watami'; __PACKAGE__->load_plugins( @PLUGINS ); __PACKAGE__->class_component_reinitialize(config => $config); 1;
package HStaff::Plugin::Jitensya; use strict; use warnings; use base 'Class::Component::Plugin'; use Perl6::Say; sub init { my($self) = @_; # 外部のDBやファイルからデータを読んでいるつもり my $pos = tell DATA; while (<DATA>) { next unless /^$self->{config}{injected}\s*:\s*(.+)$/; $self->{prop}{color} = $1; } seek DATA, $pos, 0; } sub bell : Method { my($self, $context, @args) = @_; say $self->config->{sound} . ' by ' . $self->config->{injected}; } sub color : Method { my($self, $context, @args) = @_; say $self->{prop}{color} || 'no color'; } 1; __DATA__ Naoya: blue ThirdLife: pink
package HStaff::Plugin::Nijikai; use strict; use warnings; use base 'Class::Component::Plugin'; use Perl6::Say; sub drink : Method { my($self, $context, @args) = @_; say $self->config->{where} . ' DE nonderu.'; } 1;