2008-10-23 13 views
6

Ich habe dieses Perl-Skript mit vielen definierten Konstanten von Konfigurationsdateien. Zum Beispiel:Wie kann ich Doppelungen in Konstanten reduzieren?

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

möchte ich Duplizierung von "/ etc/app1" und "/ var/log" reduzieren, aber Variablen funktioniert nicht. Auch die Verwendung zuvor definierter Konstanten funktioniert nicht im selben "use constant block". Zum Beispiel:

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

funktioniert nicht.

Die Verwendung separater "Benutze-Konstante" -Blöcke ist eine Lösung dieses Problems, die jedoch viel unnötigen Code hinzufügt.

Was ist der richtige Weg, dies zu tun?

Vielen Dank.

Antwort

7

Ich würde wahrscheinlich es so schreiben:

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; 

aber das ist immer noch eine Menge Code, aber es macht die Duplizierung entfernen und das ist ein Gewinn.

Warum sind Ihre Logdateien numerisch? Wenn sie mit 0 beginnen, ist ein Array eine bessere Wahl als ein Hash. Wenn sie benannt sind, sind sie beschreibender.

+0

Danke für die Antwort, der Logname ist nicht wirklich numerisch - ich habe sie nur so für das Beispiel geändert. –

3

Das wird leider nicht funktionieren. Der Grund dafür ist, dass Sie Funktionen ("Konstanten") verwenden, bevor sie definiert werden. Sie werten sie vor dem Aufruf an constant->import aus.

Verwenden von Variablen funktioniert nicht, da Use-Anweisungen zur Kompilierzeit ausgewertet werden. Die Zuweisung zu Variablen erfolgt nur zur Laufzeit, daher werden sie noch nicht definiert.

Die einzige Lösung, die ich geben kann, ist es in mehrere use constant Aussagen zu teilen. In diesem Fall tun zwei Aussagen (eine für LOG_DIR und CONF_DIR, eine andere für den Rest).

8

Verwendung separat „verwenden Konstante“ Blöcke tut Abhilfe dieses Problem, aber die fügt eine Menge von nicht benötigten Code.

Geht es wirklich?

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

Ich sehe nicht viele Probleme mit diesem. Sie haben den Basispfad nur in einem Punkt angegeben und berücksichtigen dabei das DRY-Prinzip. Wenn Sie base_path mit einer Umgebungsvariablen zuweisen:

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

... Sie haben dann eine preiswerte Möglichkeit, Ihre Konstante neu zu konfigurieren, ohne den Code bearbeiten zu müssen. Was ist daran nicht zu mögen? „Base_path“

Wenn Sie wirklich die sich wiederholende reduzieren wollen Verkettung, könnten Sie ein bisschen von Maschinen fügen Sie die Konstanten selbst und Faktor, der weg zu installieren:

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

Aber an diesem Punkt denke ich, die Balance hat sich von Correct nach Nasty verschoben :) Zu Beginn können Sie nicht mehr nach CONF_FILE1 grep und sehen, wo es definiert ist.

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

Je nachdem, was Sie tun, möchten Sie vielleicht überhaupt keine Konstanten. Meistens schreibe ich Sachen, die andere benutzen, um ihre Sachen zu erledigen, also löse ich dieses Problem auf eine Weise, die anderen Programmierern Flexibilität gibt. Ich mache diese Dinge zu Methoden:

sub base_log_dir { '...' } 

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

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

Indem ich es so mache, kann ich leicht Dinge erweitern oder überschreiben.

Dies zu tun, verliert jedoch den Wert der konstanten Faltung, also müssen Sie darüber nachdenken, wie wichtig das für Sie ist.

Verwandte Themen