2009-01-11 18 views
20

Estoy trabajando en un marco de prueba en Perl. Como parte de las pruebas, es posible que necesite agregar verificaciones previas o posteriores a la condición para cualquier prueba dada, pero no necesariamente para todas. Lo que tengo hasta ahora es algo así como:¿Cómo puedo determinar si existe una función Perl en el tiempo de ejecución?

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

Desafortunadamente, esto da salida a "subrutinas Indefinido & verify_precondition_TEST1 llamados a ..." si la función no existe.

¿Cómo puedo determinar de antemano si la función existe antes de intentar llamarla?

Respuesta

8

Con definido:

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, sólo pensaba en eval como lo fue en la pregunta, pero con referencias simbólicas criado con Leon Timmermans, no podía' t lo hace

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

incluso con estricta?

+1

Esta es la evaluación incorrecta. Quieres bloquear eval, no string eval. Además, las pruebas si existe una función se pueden hacer con una evaluación de todos modos. –

+0

Necesito usar eval de cadena porque $ n no se conoce en tiempo de compilación. –

+0

No, no es así. Necesita usar referencias simbólicas. Vea mi respuesta para ver un ejemplo de cómo abordarlos. –

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

o

*Package::Name::function{CODE} 

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

o simplemente viven con la excepción. Si llama a la función en una evaluación y $ @ está configurado, entonces no puede llamar a la función.

Por último, parece que es posible que desee Test :: Class en lugar de escribir esto usted mismo.

Editar: defined &function_name (o la variante no strict; defined &{ $function_name }), como se menciona en las otras respuestas, parece ser la mejor manera. UNIVERSAL :: can es lo mejor para algo que va a llamar como método (estilísticamente), y por qué molestarse en jugar con la tabla de símbolos cuando Perl le brinda la sintaxis para hacer lo que quiera.

aprendizaje ++ :)

+0

Lamentablemente estoy haciendo esto fuera de cualquier paquete, así que me sale: No puedo encontrar el método del objeto "puede" a través del paquete "principal". Además, estoy usando una versión antigua de Perl (5.002) en un entorno en el que no tengo absolutamente ningún módulo Perl instalado. –

+0

Whoa, 5.002? Creo que salió antes de que naciera :) – jrockway

+0

¿No es el 5.002 el que tiene todos los problemas de desbordamiento del búfer? :) –

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 (ningún estricto siempre es mejor que el eval de cadena) BTW, pequeño error tipográfico: s/$ nombrefunctivo/$ nombrefuncional/ – jrockway

+0

I ' d escribir eso como 'no estrictos 'refs'' solo para indicar al lector que está a punto de hacer alguna magia de referencia simbólica. :) –

+0

Sí, buen punto. –

4

que había utilizado el enfoque de León, pero cuando tenía varios paquetes, que ha fallado. No estoy seguro de por qué; Creo que se relaciona con la propagación del alcance entre espacios de nombres. Esta es la solución que se me ocurrió.

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

Referencias:
__PACKAGE__ referencia en la página perlmod.

Packages/__PACKAGE__ referencia en Perl Training Australia.

+1

El problema podría ser si ha tratado de hacer directamente como: 'if (defined & {$ package. ':: subname'})', pero así debería estar bien: 'my $ subname = $ package. ' :: sub_name '; if (definido & {$ subname}) ... ' – bor

Cuestiones relacionadas