Pregunta

Tengo este script Perl con muchas constantes definidas de archivos de configuración. Por ejemplo:

use constant  {
LOG_DIR                             => "/var/log/",
LOG_FILENAME                        => "/var/log/file1.log",
LOG4PERL_CONF_FILE                  => "/etc/app1/log4perl.conf",
CONF_FILE1                          => "/etc/app1/config1.xml",
CONF_FILE2                          => "/etc/app1/config2.xml",
CONF_FILE3                          => "/etc/app1/config3.xml",
CONF_FILE4                          => "/etc/app1/config4.xml",
CONF_FILE5                          => "/etc/app1/config5.xml",
};

Quiero reducir la duplicación de " / etc / app1 " y " / var / log " , pero el uso de variables no funciona. Además, el uso de constantes previamente definidas no funciona en el mismo bloque de constante de uso. Por ejemplo:

use constant {
LOG_DIR                             => "/var/log/",
FILE_FILENAME                       => LOG_DIR . "file1.log" 
};

no funciona.

Usando separado " use constante " los bloques solucionan este problema, pero eso agrega una gran cantidad de código innecesario.

¿Cuál es la forma correcta de hacer esto?

Gracias.

¿Fue útil?

Solución

Probablemente lo escribiría así:

use Readonly;

Readonly my $LOG_DIR            => "/var/log";
Readonly my $LOG_FILENAME       => "$LOG_DIR/file1.log";
Readonly my $ETC                => '/etc/app1';
Readonly my $LOG4PERL_CONF_FILE => "$ETC/log4perl.con";

# hash because we don't have an index '0'
Readonly my %CONF_FILES => map { 

Probablemente lo escribiría así:

<*>

Sin embargo, todavía hay mucho código, pero elimina la duplicación y eso es una victoria.

¿Por qué son numéricos sus archivos de registro? Si comienzan con 0, una matriz es una mejor opción que un hash. Si son nombrados, son más descriptivos.

=> "$ETC/config

Probablemente lo escribiría así:

<*>

Sin embargo, todavía hay mucho código, pero elimina la duplicación y eso es una victoria.

¿Por qué son numéricos sus archivos de registro? Si comienzan con 0, una matriz es una mejor opción que un hash. Si son nombrados, son más descriptivos.

.xml" } 1 .. 5;

Sin embargo, todavía hay mucho código, pero elimina la duplicación y eso es una victoria.

¿Por qué son numéricos sus archivos de registro? Si comienzan con 0, una matriz es una mejor opción que un hash. Si son nombrados, son más descriptivos.

Otros consejos

  

Usando separado " use constante " bloques   soluciona este problema, pero eso   agrega una gran cantidad de código innecesario.

¿Realmente?

use constant BASE_PATH => "/etc/app1";

use constant  {
    LOG4PERL_CONF_FILE                  => BASE_PATH . "/log4perl.conf",
    CONF_FILE1                          => BASE_PATH . "/config1.xml",
    CONF_FILE2                          => BASE_PATH . "/config2.xml",
    CONF_FILE3                          => BASE_PATH . "/config3.xml",
    CONF_FILE4                          => BASE_PATH . "/config4.xml",
    CONF_FILE5                          => BASE_PATH . "/config5.xml",
};

No veo muchos problemas con esto. Ha especificado la ruta base en un solo punto, respetando así el principio DRY. Si asigna BASE_PATH con una variable de entorno:

use constant BASE_PATH => $ENV{MY_BASE_PATH} || "/etc/app1";

... entonces tiene una forma barata de reconfigurar su constante sin tener que editar su código. ¿Qué hay para no gustar de esto?

Si realmente desea reducir la repetitiva " BASE_PATH. " En la concatenación, puede agregar un poco de maquinaria para instalar las constantes y eliminar eso:

use strict;
use warnings;

use constant BASE_PATH => $ENV{MY_PATH} || '/etc/apps';

BEGIN {
    my %conf = (
        FILE1 => "/config1.xml",
        FILE2 => "/config2.xml",
    );

    for my $constant (keys %conf) {
        no strict 'refs';
        *{__PACKAGE__ . "::CONF_$constant"}
            = sub () {BASE_PATH . "$conf{$constant}"};
    }
}

print "Config is ", CONF_FILE1, ".\n";

Pero en este punto, creo que el equilibrio se ha ido alejando de Correcto a Desagradable :) Para empezar, ya no puede hacer grep para CONF_FILE1 y ver dónde está definido.

use constant +{
    map { sprintf <*>, '/var/log' } (
        LOG_DIR            => "%s/",
        LOG_FILENAME       => "%s/file1.log",
    ),
    map { sprintf <*>, '/etc/app1' } (
        LOG4PERL_CONF_FILE => "%s/log4perl.conf",
        CONF_FILE1         => "%s/config1.xml",
        CONF_FILE2         => "%s/config2.xml",
        CONF_FILE3         => "%s/config3.xml",
        CONF_FILE4         => "%s/config4.xml",
        CONF_FILE5         => "%s/config5.xml",
    ),
};

Lamentablemente no va a funcionar. La razón de esto es que está utilizando funciones ('constantes') antes de que se definan. Los evalúas antes de la llamada a constante- > importar .

El uso de variables no funciona porque las instrucciones de uso se evalúan en tiempo de compilación. La asignación de variables solo se realiza en tiempo de ejecución, por lo que aún no se definirán.

La única solución que puedo dar es dividirla en varias declaraciones de use constant . En este caso, se harán dos declaraciones (una para LOG_DIR y CONF_DIR , otra para el resto).

Dependiendo de lo que estés haciendo, es posible que no quieras ninguna constante. Sobre todo, escribo cosas que otras personas usan para hacer sus cosas, así que resuelvo este problema de una manera que le da flexibilidad a otros programadores. Hago estas cosas en métodos:

 sub base_log_dir { '...' }

 sub get_log_file
      {
      my( $self, $number ) = @_;

      my $log_file = catfile( 
        $self->base_log_dir, 
        sprintf "foo%03d", $number
        );
      }

Al hacerlo de esta manera, puedo extender o anular las cosas fácilmente.

Sin embargo, hacer esto pierde el valor del plegamiento constante, así que debes pensar en lo importante que es eso para ti.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top