динамический вызов подпрограмм в Perl - PullRequest
0 голосов
/ 22 ноября 2011

Я немного запутался со следующим:

У меня есть функция, которая вызывает подпрограммы следующим образом:

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 -> $ рутина -> {$ param} (), $ self -> $ {рутина -> $ {парам}} () и многие другие безуспешно. Я проверил главу 9 «динамические подпрограммы» освоения perl и вопрос, подобный монахам perl , но я до сих пор не могу понять, как ссылаться на подпрограмму таким образом который представляет $ self-> updateAnotherOneSub (), или что-то подобное, что позволяет $ self быть прочитанным как параметр в этих подпрограммах.

Заранее спасибо, Кебер.

Ответы [ 2 ]

3 голосов
/ 22 ноября 2011

Это похоже на проблему X / Y.Что именно ты пытаешься сделать?Если это сокращает время загрузки, тогда вам могут быть интересны такие модули, как AutoSplit / AutoLoader.

Если вы хотите создать какую-то структуру данных подпрограмм, вы должны устанавливать анонимные подпрограммы в хеш,вместо того, чтобы давать им все имена.

Учитывая ссылку на подпрограмму:

my $code = sub {...};

, вы бы назвали это следующим образом:

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

Если вместо этого у вас есть имя подпрограммы,вы можете посмотреть код ссылки:

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'

0 голосов
/ 22 ноября 2011

Попробуйте сначала извлечь имя метода, затем оно должно работать.Я сделал небольшой тестовый скрипт, который может делать что-то, что вы хотите, поэтому:

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

Вы можете и, конечно, должны проверить, существует ли нужный метод, как сказал Эрик:

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

Важной частью здесь является то, что вы извлекаете имя метода, чтобы оно было в одной переменной;иначе Perl не поймет это для вас - и, насколько я знаю, для этого нет способа установить скобки или скобки.

...