2008-10-23 6 views
6

J'ai ce script Perl avec de nombreuses constantes définies de fichiers de configuration. Par exemple:Comment puis-je réduire la duplication dans les constantes?

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

Je veux réduire la duplication des "/ etc/app1" et "/ var/log", mais en utilisant des variables ne fonctionne pas. L'utilisation de constantes définies précédemment ne fonctionne pas dans le même "bloc constant d'utilisation". Par exemple:

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

ne fonctionne pas.

L'utilisation de blocs séparés « utilisation constante » ne contourner ce problème, mais cela ajoute beaucoup de code inutile.

Quelle est la bonne façon de faire cela?

Merci.

Répondre

7

je serais probablement écrire comme ceci:

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 { $_ => "$ETC/config$_.xml" } 1 .. 5; 

Cependant, c'est encore beaucoup de code, mais il ne supprime la duplication et c'est une victoire.

Pourquoi vos fichiers journaux numérique? Si elles commencent par 0, un tableau est un meilleur choix qu'un hachage. Si elles sont nommées, elles sont plus descriptives.

+0

Merci pour la réponse, les noms de log ne sont pas vraiment numériques - je les ai juste changés comme ça pour l'exemple. –

3

qui ne va pas au travail, malheureusement. La raison en est que vous utilisez des fonctions ('constantes') avant qu'elles ne soient définies. Vous les évaluez avant l'appel au constant->import.

Utilisation de variables ne fonctionne pas parce que les déclarations d'utilisation sont évalués au moment de la compilation. L'affectation aux variables n'est effectuée qu'à l'exécution, elles ne seront donc pas encore définies.

La seule solution que je peux donner est de le diviser en plusieurs états use constant. Dans ce cas, deux déclarations feront l'une (LOG_DIR et CONF_DIR, une autre pour le reste).

8

L'utilisation séparée « utilisation constante » blocs ne fait contourner ce problème, mais que ajoute beaucoup de code inutile.

-t-il vraiment?

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

Je ne vois pas beaucoup de problèmes avec cela. Vous avez spécifié le chemin de base en un seul point, respectant ainsi le principe DRY. Si vous attribuez base_path avec une variable d'environnement:

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

... vous avez alors un moyen pas cher de reconfigurer constante sans avoir à modifier votre code. Qu'y a-t-il de ne pas aimer à ce sujet? «Base_path »

Si vous voulez vraiment réduire le répétitif concaténation, vous pouvez ajouter un peu de machines pour installer les constantes vous et facteur de distance:

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

Mais à ce stade, je pense que la balance a basculé de Correct à Nasty :) Pour commencer, vous ne pouvez plus grep pour CONF_FILE1 et voir où il est défini.

4
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", 
    ), 
}; 
0

En fonction de ce que vous faites, vous pourriez ne pas vouloir de constantes du tout. La plupart du temps, j'écris des trucs que d'autres personnes utilisent pour faire leur travail, alors je résous ce problème d'une manière qui donne de la flexibilité aux autres programmeurs. Je fais ces choses dans les méthodes:

sub base_log_dir { '...' } 

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

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

En faisant de cette façon, je peux facilement étendre ou redéfinir les choses. Si vous perdez la valeur du pliage constant, vous devez penser à l'importance que cela représente pour vous.

Questions connexes