メソッドのフック
Posted feedbacks - Perl
メソッドって言うか, 関数に対して. (勿論メソッドにも適用可能)
無い関数に対しては, 勝手に作っちゃうけど良いっすか?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | use warnings;
use strict;
{
my %hooks = ();
sub add_hook($$&;$){
my ($class, $meth, $sub, $is_after) = @_;
my $key = "$class\0$meth";
my $orig = UNIVERSAL::can($class, $meth) || sub(@){};
unless(exists $hooks{$key}){
my $pre = [];
my $after = [];
my $hook = [$pre, $after];
$hooks{$key} = $hook;
{
no strict;
no warnings;
my $proto = defined(prototype $orig) ? "(".prototype($orig).")" : "";
*{"${class}::${meth}"} = eval qq{ sub ${proto}{
use strict;
foreach my \$fun (\@\$pre)
{
\$fun->();
}
my \@R = ();
my \$R = undef;
if(wantarray)
{
\@R = \$orig->(\@_);
}
else
{
\$R = \$orig->(\@_);
}
foreach my \$fun (\@\$after)
{
\$fun->();
}
wantarray ? \@R : \$R;
} };
}
}
push @{$hooks{$key}->[$is_after ? 1 : 0]}, $sub;
}
}
# TEST
use Data::Dumper;
{
package hoge;
sub hemo(){
print "HEMO\n";
(wantarray ? (1,2,3) : [1,2,3])
}
}
add_hook(hoge => hemo => sub(){
print "pre1\n";
});
add_hook(hoge => hemo => sub(){
print "pre2\n";
});
add_hook(hoge => hemo => sub(){
print "after1\n";
},1);
add_hook(hoge => hemo => sub(){
print "after2\n";
},1);
print join "-", hoge::hemo;
print "\n\n\n";
print Dumper scalar hoge::hemo;
|
Perlの関数アトリビュートを使ってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #!/usr/bin/perl
use strict;
use warnings;
package HookAttribute;
use Attribute::Handlers;
sub Hook: ATTR(CODE) {
my (undef, undef, $referent, undef, $args) = @_;
$args = [$args] unless ref($args) eq "ARRAY";
my $hook_before = shift(@$args) eq "Before";
no strict "refs";
no warnings "redefine";
for my $funcname (@$args) {
next unless defined *{$funcname}{CODE};
my $funcref = \&{$funcname};
*$funcname = $hook_before
? sub { $referent->(@_); goto &$funcref }
: sub { $funcref->(@_); $referent->(@_) }; #callerなどが狂う
}
}
#テストコード
package Foo;
use Perl6::Say;
sub new { bless {}, shift }
sub foo { say "foo" }
package FooHooks;
use base qw/HookAttribute/;
use Perl6::Say;
sub bar: Hook("Before", qw/Foo::foo/) { say "bar" }
sub baz: Hook("After", qw/Foo::foo/) { say "baz" }
Foo->new->foo;
|


todogzm
#6017()
Rating0/8=0.00
例えば、あるクラスのあるメソッドを実行する前に他の処理を呼びたい(例えばログやトランザクション開始など)。 また、そのメソッドの終了後にも何らかの後処理を呼びたい(トランザクション終了など)。
そのような、メソッドに対するフック処理を書いてください。 ライブラリを使用してメソッドのフックを実現した場合は ライブラリの名前を紹介してくれると助かります。
[ reply ]