动态调用perl中的子程序

时间:2011-11-21 21:55:59

标签: perl dynamic this subroutine

我有点搞砸了以下内容:

我有一个以下列方式调用子程序的函数:

sub someFunction {
    my $self = shift;
    my $type = $self->{'type'};

    if($type eq 'one_subroutine') {
        $self->updateOneSubroutine();
    }
    elsif($type eq 'another_one_sub') {
        $self->updateAnotherOneSub();
    }
(...)
    else {
        die "Unsupported '$type'";
    }

我必须改变它,让每个子程序在自己的文件中编码,包括所有可用文件,并自动调用里面的子程序。

我在测试文件中使用以下代码执行此操作:

# Assume a routines subdir with one_subroutine.pm file with 
sub updateOneSubroutine(){
    $self = shift;
    $self->doSomeThings();

    (...) #my code
}
1;

test.pl

# Saves in routines hash_ref a pair of file_name => subRoutineName for each file in routines subdir.
# This will be used later to call subroutine.
opendir(DIR,"lib/routines") or die "routines directory not found";
for my $filename (readdir(DIR)) {
    if($filename=~m/\.pm$/){
        # includes file
        require "lib/routines/$filename";
        # get rid of file extension
        $filename=~s/(.*)\.pm/$1/g;
        my $subroutine = "update_${file}";
        # camelizes the subroutine name
        $subroutine=~s/_([a-z0-9])/\u$1/g;
        $routine->{ $filename }  = $subroutine;
    }
}

{
    no strict "refs";
    $routine->{$param}();
}

其中param类似于“one_subroutine”,它与可用的文件名匹配。

由于每个子程序在调用中都收到$ self,我应该通过$ self-> something();

调用例程

我尝试过$ self-> $ routine-> {$ param}(),$ self-> $ {routine-> $ {param}}()以及许多其他事情都没有成功。我已经检查了chapter 9 "dynamic subroutines" of mastering perla similar question to perl monks,但我仍然无法弄清楚如何以代表$ self-> updateAnotherOneSub()的方式引用子例程,或类似的东西让$在这些子程序中,自我被读作一个参数。

提前致谢,Keber。

2 个答案:

答案 0 :(得分:3)

这看起来有点像X / Y问题。你究竟想做什么?如果要减少加载时间,那么您可能会对AutoSplit / AutoLoader等模块感兴趣。

如果要创建某种子例程的数据结构,则应该将匿名子安装到哈希中,而不是给它们所有名称。

给出子程序参考:

my $code = sub {...};

你会把它称为:

$self->$code(...);

如果你有一个子程序名,你可以查找coderef:

my $code = 'Package::With::The::Subroutines'->can('method_name');

如果成功(检查),那么您可以使用$self->$code(...)来调用它。


鉴于此代码:

{
    no strict "refs";
    $routine->{$param}();
}

您可以将$self传递给例程:

{
    no strict "refs";
    $routine->{$param}($self);
}

或者你可以像我上面can所做的那样接近它:

'package'->can($routine->{$param})->($self)

如果您不想关闭strict 'refs'

答案 1 :(得分:0)

首先尝试提取方法名称,然后它应该工作。我做了一个小的测试脚本,可以做你想做的事情,所以:

my $method = $routine->{$param};
$self->$method->();

你可以当然应该检查,如果存在所需的方法,如埃里克所说:

if ($self->can($method)) {
    $self->$method->();
}

这里的重要部分是,您提取方法名称,以便将其包含在单个变量中;否则perl不会为你解决这个问题 - 据我所知,没有办法设置parens或braces这样做。