Question

I'm working on a test framework in Perl. As part of the tests, I may need to add precondition or postcondition checks for any given test, but not necessarily for all of them. What I've got so far is something like:

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

Unfortunately, this outputs "Undefined subroutine &verify_precondition_TEST1 called at ..." if the function does not exist.

How can I determine ahead of time whether the function exists, before trying to call it?

Was it helpful?

Solution

With defined:

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: hmm, I only thought of eval as it was in the question but with symbolic references brought up with Leon Timmermans, couldn't you do

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

even with strict?

OTHER TIPS

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

or

*Package::Name::function{CODE}

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

or just live with the exception. If you call the function in an eval and $@ is set, then you can't call the function.

Finally, it sounds like you may want Test::Class instead of writing this yourself.

Edit: defined &function_name (or the no strict; defined &{ $function_name } variant), as mentioned in the other answers, looks to be the best way. UNIVERSAL::can is best for something you're going to call as a method (stylistically), and why bother messing around with the symbol table when Perl gives you syntax to do what you want.

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") {
    ...
}

I had used Leon's approach, but when I had multiple packages, it failed. I'm not sure precisely why; I think it relates to the propagation of scope between namespaces. This is the solution I came up with.

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});

References:
__PACKAGE__ reference on the perlmod page.

Packages/__PACKAGE__reference on Perl Training Australia.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top