Как я могу определить, существует ли функция Perl во время выполнения? - PullRequest
22 голосов
/ 12 января 2009

Я работаю над тестовым фреймворком в Perl. В рамках тестов мне может понадобиться добавить предварительные или постусловные проверки для любого данного теста, но не обязательно для всех. То, что я получил до сих пор, выглядит примерно так:

eval "&verify_precondition_TEST$n";
print $@ if $@;

К сожалению, это выводит "Неопределенную подпрограмму & verify_precondition_TEST1, вызванную в ...", если функция не существует.

Как я могу заранее определить, существует ли функция, прежде чем пытаться ее вызвать?

Ответы [ 4 ]

37 голосов
/ 12 января 2009
Package::Name->can('function')

или

*Package::Name::function{CODE}

# or no strict; *{ "Package::Name::$function" }{CODE}

или просто жить с исключением. Если вы вызываете функцию в eval и установлена ​​$ @, то вы не можете вызвать функцию.

Наконец, звучит так, что вы можете захотеть Test :: Class вместо того, чтобы писать это самостоятельно.

Редактировать: defined &function_name (или вариант no strict; defined &{ $function_name }), как упоминалось в других ответах, выглядит наилучшим образом. UNIVERSAL :: can лучше всего подходит для того, что вы собираетесь вызывать как метод (стилистически), и зачем возиться с таблицей символов, когда Perl дает вам синтаксис для выполнения того, что вы хотите.

Обучение ++:)

17 голосов
/ 12 января 2009
sub function_exists {    
    no strict 'refs';
    my $funcname = shift;
    return \&{$funcname} if defined &{$funcname};
    return;
}

if (my $subref = function_exists("verify_precondition_TEST$n") {
    ...
}
9 голосов
/ 12 января 2009

С определено:

if (eval "defined(&verify_precondition_TEST$n)") {
    eval "&verify_precondition_TEST$n";
    print $@ if $@;
}
else {
    print "verify_precondition_TEST$n does not exist\n";
}

РЕДАКТИРОВАТЬ: хм, я думал только о Eval, как это было в вопросе, но с символическими ссылками, воспитанными с Леоном Тиммермансом, вы не могли сделать

if (defined(&{"verify_precondition_TEST$n"}) {
    &{"verify_precondition_TEST$n"};
    print $@ if $@;
}
else {
    print "verify_precondition_TEST$n does not exist\n";
}

даже со строгим?

5 голосов
/ 04 августа 2009

Я использовал подход Леона, но когда у меня было несколько пакетов, он потерпел неудачу. Я не уверен точно, почему; Я думаю, что это относится к распространению области между пространствами имен. Это решение, которое я придумал.

my %symbols = ();
my $package =__PACKAGE__; #bring it in at run-time
{
    no strict;
    %symbols = %{$package . "::"}; #See Symbol Tables on perlmod
}
print "$funcname not defined\n" if (! defined($symbols{$funcname});

Ссылки:
__ ПАКЕТ __ ссылка на страницу perlmod.

Пакеты / __ ПАКЕТ __ ссылка на Perl Training Australia.

...