Devel::REPLのプラグイン(1)
めも。
Devel::REPLの、プラグインの呼び出しには(たぶん)2種類あって、
1つめがDevel::PERLに定義されてるメソッドをhookする(before,after,aroundする)。
こっちのタイプは単純にMoose::Roleを使ってる。
Plugin::Colorsとかだと、
package Devel::REPL::Plugin::Colors; use Moose::Role; ... around print => sub { my $orig = shift; my $self = shift; print {$self->out_fh} color($self->normal_color); $orig->($self, @_); print {$self->out_fh} color('reset'); };
みたいな感じでDevel::REPL->print()にhookしてる。
このaroundとかが、どこでDevel::REPL->print()に設定されるかというと、
MooseX::Object::Pluggable->_load_and_apply_role()の中の、$role->meta->apply($self)の部分。
package MooseX::Object::Pluggable; ... sub _load_and_apply_role{ my ($self, $role) = @_; die("You must provide a role name") unless $role; eval { Class::MOP::load_class($role) }; confess("Failed to load role: ${role} $@") if $@; carp("Using 'override' is strongly discouraged and may not behave ". "as you expect it to. Please use 'around'") if scalar keys %{ $role->meta->get_override_method_modifiers_map }; $role->meta->apply( $self ); return 1; }
$roleには"Devel::Plugin::Colors"とか、プラグインクラス名が入ってて、
$role->metaはMoose::Meta::Role。たぶんuse Moose::Roleするとexportしてくれるのかな。んでapply()する。
Moose::Meta::Role->apply()は既存のインスタンスとかクラスとかにMixin(?)するメソッドで、
定義されてるメソッドだけじゃなくてaroundとかbeforeとかも一緒にやってくれる。
わすれないようにサンプル。
use strict; use warnings; package Foo; sub new { bless {}, shift } sub hello { print "hello\n" } package Foo::Plugin::Hello; use Moose::Role; before 'hello' => sub { print "before hello\n"; }; sub buy { print "buy\n" } package main; my $foo = Foo->new; Foo::Plugin::Hello->meta->apply($foo); $foo->hello(); $foo->buy(); #結果 before hello hello buy
まあこんな感じでDevel::REPLのメソッドが呼ばれるたびに、Pluginのaroundやらbeforeやらが呼ばれるみたい。