2009-01-11 15 views
20

Pracuję nad szkieletem testowym w Perlu. W ramach testów może być konieczne dodanie warunku wstępnego lub testów końcowych dla danego testu, ale niekoniecznie dla wszystkich z nich. Co mam tak daleko jest coś takiego:Jak ustalić, czy funkcja Perl istnieje w środowisku wykonawczym?

eval "&verify_precondition_TEST$n"; 
print [email protected] if [email protected]; 

Niestety, ten wyprowadza „Undefined podprogramów & verify_precondition_TEST1 zwane w ...”, jeśli funkcja nie istnieje.

Jak ustalić z góry, czy funkcja istnieje, przed próbą połączenia?

Odpowiedz

8

Z zdefiniowane:

if (eval "defined(&verify_precondition_TEST$n)") { 
    eval "&verify_precondition_TEST$n"; 
    print [email protected] if [email protected]; 
} 
else { 
    print "verify_precondition_TEST$n does not exist\n"; 
} 

EDIT: hmm, ja tylko myślałem o eval, jak to było w pytaniu, ale z odniesieniami symbolicznymi wychowani Leon Timmermans, mogłem” możesz zrobić

if (defined(&{"verify_precondition_TEST$n"}) { 
    &{"verify_precondition_TEST$n"}; 
    print [email protected] if [email protected]; 
} 
else { 
    print "verify_precondition_TEST$n does not exist\n"; 
} 

nawet przy ścisłym?

+1

To jest niewłaściwy eval. Chcesz blokować eval, a nie string eval. Poza tym testowanie, czy funkcja istnieje, może być wykonane za pomocą ewaluacji. –

+0

Potrzebuję użyć string eval, ponieważ $ n nie jest znane podczas kompilacji. –

+0

Nie, nie. Musisz użyć symbolicznych odniesień. Zobacz moją odpowiedź na przykład, jak do nich podejść. –

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

lub

*Package::Name::function{CODE} 

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

lub po prostu żyć z wyjątkiem. Jeśli wywołasz funkcję w eval i ustawisz $ @, nie możesz wywołać tej funkcji.

Wreszcie, wydaje się, że możesz chcieć Test :: Class zamiast pisać to sam.

Edytuj: defined &function_name (lub wariant no strict; defined &{ $function_name }), jak wspomniano w innych odpowiedziach, wygląda najlepiej. UNIVERSAL :: can jest najlepszy dla czegoś, co nazwiesz metodą (stylistycznie) i dlaczego zawracasz sobie głowę tabelą symboli, gdy Perl daje ci składnię, by robić to, co chcesz.

Learning ++ :)

+0

Niestety robię to poza jakimkolwiek pakietem, więc otrzymuję: Nie mogę zlokalizować metody obiektu "może" przez pakiet "główny". Używam też starodawnej wersji Perla (5.002) w środowisku, w którym nie mam absolutnie żadnych modułów Perla. –

+0

Whoa, 5,002? Myślę, że wyszło przed moim urodzeniem :) – jrockway

+0

Czy nie jest 5.002 z wszystkimi problemami z przepełnieniem bufora? :) –

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

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

+1 (nie surowe jest zawsze lepsze niż string eval) BTW, malutka literówka: s/$ functname/$ funcname/ – jrockway

+0

Ja ' piszcie to jako "nie surowe", tylko po to, aby zauważyć czytelnikowi, że macie zamiar wykonać symboliczną magię odniesienia. :) –

+0

Tak, dobra uwaga. –

4

Użyłem podejścia Leona, ale gdy miałem wiele pakietów, nie udało się. Nie jestem pewien dokładnie dlaczego; Myślę, że dotyczy on propagacji zakresu między przestrzeniami nazw. To jest rozwiązanie, które wymyśliłem.

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

Referencje:
__PACKAGE__ odniesienia na stronie perlmod.

Packages/__PACKAGE__ odniesienie do szkolenia Perl Australia.

+1

Problem może być, jeśli próbujesz zrobić bezpośrednio jak: 'if (defined & {$ package. ':: subname'})', ale tak jak powinno być dobrze: 'my $ subname = $ package. ' :: sub_name "; if (zdefiniowane i {$ subname}) ... ' – bor

Powiązane problemy