動的にclass methodを呼びたい場合は割と簡単で、以下のように書ける
package Foo;
use strict;
use feature 'say';
sub new { bless {}, shift }
sub sum {
my $self = shift;
my ( $x, $y ) = @_;
say $x + $y;
}
package main;
use strict;
use feature 'say';
my $obj = Foo->new;
my $func = 'sum';
if ( $obj->can($func) ) {
$obj->$func( 1, 2 );
}
else {
say "No such method => $func";
}
しかし、動的にsubroutineを呼びたい場合はちょっと泥臭くなる
use strict;
use feature 'say';
sub sum {
my ( $x, $y ) = @_;
say $x + $y;
}
my $func = 'sum';
{
local $@;
eval "$func(1,2)";
if ($@) {
say "Oops! $@";
}
}
{
my $code = do {
no strict 'refs';
*{$func}{CODE};
};
if ($code) {
$code->( 1, 2 );
}
else {
say "Oops! Undefined subroutine $func";
}
}
eval
でstringを評価するか、no strict 'refs'
してからsymbol tableを確認する方法があります。
速度面を考えるとeval
したくないし、かと言ってno strict 'refs'
をして直接symbol tableを触りたくない。
こう言った泥臭いことはmoduleに隠蔽しちゃうのがいいんじゃないかと思ったので、Sub::Applyを書きました。
Sub::Applyの使用例
use strict;
use feature 'say';
use Sub::Apply qw(apply apply_if);
sub sum {
my ( $x, $y ) = @_;
say $x + $y;
}
my $func = 'sum';
{
# $funcがない場合、croak
apply($func, 1, 2);
}
{
# $funcがない場合、carp
local $Sub::Apply::WARNING = 1;
apply_if($func, 1, 2);
}
{
# $funcがなくても何もしない
apply_if($func, 1, 2);
}
CPANとgithubにupしてあります
現在のversion(0.04)では、printf等のcore functionは呼び出せませんので注意してください。
__PACKAGE__->can($func)->(1,2); でできますね。
返信削除method呼び出しなら@ISAを辿ってくれるcanの方がいいと思います。
返信削除function呼び出し(Foo::sum())だと@ISAは辿らない挙動ですので、それに合わせたかったのです。
https://gist.github.com/1380057