Class::Component の run_hook にPlaggerライクな rule をかます(その2)
昨日の続き。
今回は新たに定義したRuleHookアトリビュートを使ってruleをかませました。こっちのほうが、run_hookを上書きすることも無く、フレームワークとして綺麗ですね。
他にもいい方法あるかな?
変更点は…
package Naoya; use strict; use warnings; use base qw/Class::Component/; __PACKAGE__->load_plugins(qw/ Jitensya /); 1;
非常にシンプルになりました。run_hookのオーバーライドはやめて、Autocall::InjectMethodコンポーネントもこの例では必要ないので消しました。
package Naoya::Plugin::Jitensya; use strict; use warnings; use base 'Naoya::Plugin'; sub ruled : RuleHook('bell') { my($self, $context, $args) = @_; print $self->config->{sound}, "\n"; } sub normal : Hook('force_bell') { my($self, $context, $args) = @_; print $self->config->{sound}, "\n"; } 1;
rule_hookを無くした代わりに、bellフックのアトリビュートをRuleHookに変えています。
そのほかのファイルもruleの取り回し関係のコードは不必要になった為、削除してます。
でキモとなるアトリビュートのコードがこれ。
package Naoya::Attribute::RuleHook; use strict; use warnings; use base 'Class::Component::Attribute'; sub register { my $class = shift; my($plugin, $c, $method, $value, $code) = @_; $c->register_hook( $value => { plugin => $plugin, method => $method } ); no strict 'refs'; no warnings 'redefine'; *{ ref($plugin) . "::$method" } = sub { my($self, $context, $args) = @_; return unless $self->rule->dispatch($self, $args); $code->($self, $context, $args); }; } 1;
フックメソッドを再定義してます。rule通らなかったらリターン、rule通ったらオリジナルのコードを実行。
これで前回と同じテストは通りました。けど、もっと厳密にテストすると実は不具合あるかもしんない。
追記:
メソッドのredefineはしないほうがやっぱいい。内部でコード(リファレンス)をキャッシュしてる関係で、意図しない動きが発生する場合がある。
コンポーネントでオレオレrun_hookを実装するのがベストかな。