2010-09-07 24 views
12
open $FP, '>', $outfile or die $outfile." Cannot open file for writing\n"; 
  • tengo esta declaración muchas veces en mi código.Escribir una macro en Perl

  • Quiero mantener el formato igual para todas esas declaraciones, de modo que cuando algo se cambia, solo se cambia en un lugar.

  • En Perl, ¿cómo puedo solucionar esta situación?

  • ¿Debo usar macros o funciones?

he visto este hilo SO How can I use macros in Perl?, pero no dice mucho acerca de cómo escribir una macro en general como

#define fw(FP, outfile) open $FP, '>', \ 
     $outfile or die $outfile." Cannot open file for writing\n"; 

Respuesta

25

En primer lugar, usted debe escribir que a medida:

open my $FP, '>', $outfile or die "Could not open '$outfile' for writing:$!"; 

incluyendo la razón por la open fallidos.

Si desea encapsular eso, se puede escribir:

use Carp; 

sub openex { 
    my ($mode, $filename) = @_; 
    open my $h, $mode, $filename 
     or croak "Could not open '$filename': $!"; 
    return $h; 
} 

# later 

my $FP = openex('>', $outfile); 

que comienzan con Perl 5.10.1, autodie está en el núcleo y segundo testamento Chas. Recomendación de Owens para usarlo.

+2

Yo diría "no puedo" en lugar de "no puedo" porque quién sabe cuál es el estado actual de ese archivo; solo sabemos cuál era el estado cuando intentamos abrirlo (de ahí el tiempo pasado). Por supuesto, eso es una suficiencia sin sentido. Podrías decir "Bang for $ filename: $!" Con la misma facilidad. –

+0

Ah, y 'corelist' dice que Perl 5.10.1 fue la primera versión con' autodie' en el núcleo y el [delta] (http://perldoc.perl.org/perl5101delta.html#New- Modules- and -Pragmata) respalda eso. –

+0

@Chas - editado. @Sinan - +1 por "$!". Los mensajes de error legibles y accionables son un arte a menudo infravalorado en el desarrollo de software. – DVK

11

Perl 5 Realmente no tiene macros (hay filtros fuente , pero son peligrosos y feos, tan feos que incluso no te vincularé con la documentación). Una función puede ser la opción correcta, pero descubrirá que dificulta que las personas nuevas lean su código. Una mejor opción puede ser utilizar el pragma autodie (es el núcleo a partir de Perl 5.10.1) y simplemente cortar la parte or die.

Otra opción, si usa Vim, es usar snipMate. Basta con escribir fw<tab>FP<tab>outfile<tab> y produce

open my $FP, '>', $outfile 
    or die "Couldn't open $outfile for writing: $!\n"; 

El texto es snipMate

snippet fw 
    open my $${1:filehandle}, ">", $${2:filename variable} 
     or die "Couldn't open $$2 for writing: $!\n"; 

    ${3} 

creo que otros editores tienen capacidades similares, pero yo soy un usuario de Vim.

7

Hay varias maneras de manejar algo similar a una macro de C en Perl: un filtro de fuente, una subrutina, Template :: Toolkit o usar funciones en su editor de texto.

Filtros Fuente

Si tienes que tienen una macro C/CPP estilo preprocesador, es posible escribir una en Perl (o, en realidad, cualquier idioma) utilizando una compilación previa source filter. Puede escribir clases de Perl bastante simples a complejas que operan en el texto de su código fuente y realizar transformaciones antes de que el código vaya al compilador de Perl. Incluso puede ejecutar su código Perl directamente a través de un preprocesador CPP para obtener el tipo exacto de macroexpansiones que obtiene en C/CPP usando Filter::CPP.

Damian Conway's Filter::Simple es parte de la distribución de núcleos Perl.Con Filter :: Simple, podría escribir fácilmente un módulo simple para realizar la macro que está describiendo. Un ejemplo:

package myopinion; 
# save in your Perl's @INC path as "myopinion.pm"... 
use Filter::Simple; 
FILTER { 
    s/Hogs/Pigs/g; 
    s/Hawgs/Hogs/g; 
    } 
1; 

A continuación, un archivo Perl:

use myopinion; 
print join(' ',"Hogs", 'Hogs', qq/Hawgs/, q/Hogs/, "\n"); 
print "In my opinion, Hogs are Hogs\n\n"; 

Salida:

Pigs Pigs Hogs Pigs 
In my opinion, Pigs are Pigs 

Si reescribiste el filtro para hacer la sustitución de la macro deseada, Filtro :: Simple debería funcionar bien Filter :: Simple puede restringirse a partes de su código para crear subestaciones, como la parte ejecutable pero no la parte POD; solo en cuerdas; solo en código

En mi experiencia, los filtros de fuente no se usan ampliamente. En su mayoría los he visto con intentos poco convincentes de cifrar el código fuente de Perl o el humorístico Perl obfuscators. En otras palabras, sé que se puede hacer de esta manera, pero personalmente no sé lo suficiente sobre ellos como para recomendarlos o decirles que no los utilicen.

subrutinas

Sinan Unur openex subroutine es una buena manera de lograr esto. Sólo añadiré que un lenguaje común más antiguo que se pueden ver consiste en pasar una referencia a un typeglob así:

sub opensesame { 
    my $fn=shift; 
    local *FH; 
    return open(FH,$fn) ? *FH : undef; 
} 

$fh=opensesame('> /tmp/file'); 

Leer perldata de por qué es así ...

Template Toolkit

Template::Toolkit se puede utilizar para procesar el código fuente de Perl. Por ejemplo, podría escribir una plantilla a lo largo de las líneas de:

[% fw(fp, outfile) %] 

en ejecución que a través de la plantilla :: Toolkit puede dar lugar a la expansión y la sustitución de:

open my $FP, '>', $outfile or die "$outfile could not be opened for writing:$!"; 

Plantilla :: Toolkit se utiliza con mayor frecuencia para separar el HTML desordenado y otro código de presentación del código de la aplicación en aplicaciones web. Template :: Toolkit se desarrolla muy activamente y está bien documentado. Si su único uso es un macro del tipo que está sugiriendo, puede ser excesivo.

editores de texto

Chas. Owens tiene un method usando Vim. Uso BBEdit y podría escribir fácilmente una Fábrica de Textos para reemplazar el esqueleto de un abierto con el abierto preciso y evolutivo que quiero usar. Alternativamente, puede colocar una plantilla de finalización en su directorio "Recursos" en la carpeta "Perl". Estos esqueletos de finalización se utilizan cuando presiona la serie de teclas que define. Casi cualquier editor serio tendrá una funcionalidad similar.

Con BBEdit, incluso puede usar el código Perl en su lógica de reemplazo de texto. Yo uso Perl::Critic de esta manera. Puede usar Template::Toolkit dentro de BBEdit para procesar las macros con cierta inteligencia. Se puede configurar para que la plantilla no cambie el código fuente hasta que genere una versión para probar o compilar; el editor esencialmente está actuando como un preprocesador.

Dos posibles problemas con el uso de un editor de texto. Primero es una transformación de una vía/una vez.Si desea cambiar lo que hace su "macro", no puede hacerlo, ya que el texto anterior de "macro" ya se utilizó. Tienes que cambiarlos manualmente. El segundo problema potencial es que si usa un formulario de plantilla, no puede enviar la versión de macro del código fuente a otra persona porque el preprocesamiento se está realizando dentro del editor.

¡No haga esto!

Si escribe perl -h para obtener parámetros de comando válida, una opción que puede ver es:

-P    run program through C preprocessor before compilation 

tentador! Sí, puede ejecutar su código Perl a través del preprocesador C y expandir las macros estilo C y tener #defines. Deja esa pistola; alejarse; no lo hagas Hay muchas incompatibilidades de plataforma e incompatibilidades de lenguaje.

Usted recibe cuestiones como esta:

#!/usr/bin/perl -P 
#define BIG small 
print "BIG\n"; 
print qq(BIG\n); 

Lienzo:

BIG 
small 

En Perl 5.12 el interruptor -P se ha eliminado ...

Conclusión

Los la solución más flexible aquí es solo escribir una subrutina. Todo su código es visible en la subrutina, se cambia fácilmente y es una llamada más corta. Ningún inconveniente real aparte de la legibilidad de su código potencialmente.

Template :: Toolkit es ampliamente utilizado. Puede escribir reemplazos complejos que actúan como macros o incluso más complejos que las macros de C. Si su necesidad de macros vale la curva de aprendizaje, use Template :: Toolkit.

Para casos muy simples, utilice las transformaciones de una vía en un editor.

Si realmente quiere macros de estilo C, puede usar Filter::CPP. Esto puede tener las mismas incompatibilidades que el interruptor perl -P. No puedo recomendar esto; solo aprende el camino de Perl.

Si desea ejecutar Perl one liners y Perl regexs contra su código antes de compilar, use Filter :: Simple.

Y no use el interruptor -P. No puede en las versiones más nuevas de Perl de todos modos.

0

Para algo así como abrir creo que es útil incluir cerca en su rutina factorizada. Aquí hay un enfoque que parece un poco extraño, pero contiene un típico lenguaje de apertura/cierre.

 
sub with_file_do(&$$) { 
    my ($code, $mode, $file) = @_; 
    open my $fp, '>', $file or die "Could not open '$file' for writing:$!"; 
    local $FP = $fp; 
    $code->(); # perhaps wrap in an eval 
    close $fp; 
} 

# usage 
with_file_do { 
    print $FP "whatever\n"; 
    # other output things with $FP 
} '>', $outfile; 

Tener los parametros especificados abiertas al final es un poco extraño, pero le permite evitar tener que especificar el sub palabra clave.

Cuestiones relacionadas