Class::Component その2

※ 例文中の個人名などは架空のものです。

やりたいこと

  • 人によって自転車の色は異なる。色の情報は外部のデータファイルとかDBとかにある。色の情報は最初に調べておいて、聞かれたらすぐに答えられるようにしておきたい。
  • やれることは全部やりたい。

やったこと

妥当かどうかわからないすけどやったこと。

  • Pluginが呼ばれる前に外部データを読むとかの初期化処理をしたい。でもってその初期化処理は、Pluginされたエッジクラスに応じて変化させたい。
    • エッジクラス (NaoyaとかKanjiManとか) で、config に { injected => __PACKAGE__ } を詰める。
    • Plugin (Jitensyaとか) は、newの中で$self->initが呼ばれる。なのでここで初期化処理をやる。
      • Pluginでは $self->config->{injected} でエッジクラスで詰めたデータがとれる。
      • initでもこれを参照して、この値に応じて初期化処理を変えたりなんかしちゃう。
  • Pluginされたメソッドを全部呼びたい。
    • Naoya->new->allで、injectされたPluginのMethodを全部呼ぶようにする。
      • NaoyaのスーパークラスのHStaffでall関数を定義。
      • $self->class_component_methods で、injectされた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;