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: pinkpackage 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;