2008-10-30 14 views
41

Tengo el siguiente código Perl que se basa en Term::ReadKey para obtener el ancho del terminal; A mi compilación de NetBSD le falta este módulo, por lo que quiero establecer el ancho del terminal por defecto en 80 cuando falta el módulo.¿Cómo puedo verificar si tengo un módulo Perl antes de usarlo?

No puedo averiguar cómo usar un módulo de forma condicional, sabiendo de antemano si está disponible. Mi implementación actual simplemente se cierra con un mensaje que dice que no puede encontrar Term::ReadKey si está ausente.

#/usr/pkg/bin/perl -w 
# Try loading Term::ReadKey 
use Term::ReadKey; 
my ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize(); 
my @p=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97); 
my $plen=$#p+1; 
printf("num |".("%".int(($wchar-5)/$plen)."d") x $plen."\n",@p); 

estoy usando Perl 5.8.7 y 5.8.8 en NetBSD en CygWin Me puedes ayudar a implementar esto en mi script de manera más efectiva?

+3

En mi opinión, ya sea el título está mal, o todas las respuestas (excepto, quizás, el que utiliza el módulo de carga :: :: condicional, si se utiliza check_install()) que están mal .El título pregunta cómo marcar "si tengo un módulo Perl * antes de usarlo *". Todas las respuestas usan alguna variación de "detectar errores con eval * mientras * requiere/cargar/usarlo". –

Respuesta

79

he aquí una solución escueto que no requiere otro módulo:

my $rc = eval 
{ 
    require Term::ReadKey; 
    Term::ReadKey->import(); 
    1; 
}; 

if($rc) 
{ 
    # Term::ReadKey loaded and imported successfully 
    ... 
} 

Tenga en cuenta que todas las respuestas a continuación (Espero que estén por debajo de éste :-) que el uso eval { use SomeModule } están equivocados porque use las declaraciones se evalúan en tiempo de compilación, independientemente de dónde aparezcan en el código. Entonces, si SomeModule no está disponible, la secuencia de comandos morirá inmediatamente después de la compilación.

(A eval cadena de un comunicado use también funcionará (eval 'use SomeModule';), pero no hay análisis sentido y compilar código de nuevo en tiempo de ejecución, cuando la pareja require/import hace lo mismo, y es sometido a control de sintaxis en tiempo de compilación de boot.)

Finalmente, tenga en cuenta que mi uso de eval { ... } y [email protected] aquí es sucinto a los fines de este ejemplo. En el código real, debe usar algo como Try::Tiny, o al menos be aware of the issues it addresses.

+0

D'oh, debería haber pensado en eso primero. +1 – ephemient

+1

Sí que realmente funciona, y el punto y coma después del bloque eval es muy importante. – dlamblin

+8

Evite confiar en $ @ tanto como sea posible. F.ex., algunos módulos podrían establecer $ @ como efecto secundario mientras se cargan sin lanzar una excepción. La mejor opción es confiar en el hecho de que 'eval' devolverá undef cuando se capture una excepción, es decir. 'if (eval" use Term :: ReadKey ") {...}'. –

10

Consulte el módulo CPAN Module::Load::Conditional. Hará lo que quieras.

+5

Por supuesto, eso solo funciona si tiene uno instalado también. Probablemente sea una mejor solución si lo hace. – tvanfosson

+0

Sí ... No puedo garantizar que tenga esa. Y mientras Detect :: Module es, no enumera todos los módulos en su $ installed-> modules() devuelto la lista de nombres de módulos. – dlamblin

6

La respuesta clásica (que se remonta a Perl 4, al menos, mucho antes de que hubiera un 'uso') era 'requerir()' un módulo. Esto se ejecuta cuando se ejecuta el script, en lugar de cuando se compila, y puede probar si tiene éxito o no y reaccionar de manera adecuada.

4

Y si necesita una versión específica del módulo:

my $GOT_READKEY; 
BEGIN { 
    eval { 
     require Term::ReadKey; 
     Term::ReadKey->import(); 
     $GOT_READKEY = 1 if $Term::ReadKey::VERSION >= 2.30; 
    }; 
} 


# elsewhere in the code 
if ($GOT_READKEY) { 
    # ... 
} 
4
if (eval {require Term::ReadKey;1;} ne 1) { 
# if module can't load 
} else { 
Term::ReadKey->import(); 
} 

o

if (eval {require Term::ReadKey;1;}) { 
#module loaded 
Term::ReadKey->import(); 
} 

Nota: el 1; sólo se ejecuta si require Term::... cargado correctamente.

0

Creo que no funciona cuando se usan variables. Por favor, compruebe this link que explica que también se puede utilizar con variables

$class = 'Foo::Bar'; 
     require $class;  # $class is not a bareword 
    #or 
     require "Foo::Bar"; # not a bareword because of the "" 

La función requerirá buscará el archivo "Foo :: Bar" en la matriz @INC y se quejará de que no encuentra "Foo :: Bar " ahí. En este caso se puede hacer:

eval "require $class"; 
Cuestiones relacionadas