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


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

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

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

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

4 21

4 ответа:

С определенными:

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

EDIT: Хм, я думал только об эвале, как это было в вопросе, но с символическими ссылками, поднятыми с Леоном Тиммермансом, не могли бы вы сделать

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

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

Package::Name->can('function')

Или

*Package::Name::function{CODE}

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

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

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

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

Learning++ :)

sub function_exists {    
    no strict 'refs';
    my $funcname = shift;
    return \&{$funcname} if defined &{$funcname};
    return;
}

if (my $subref = function_exists("verify_precondition_TEST$n") {
    ...
}

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

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.

Packages / _ _ PACKAGE _ _ ссылка на Perl Training Australia.