2008-10-23 56 views
6

我有这个Perl脚本与许多定义的常量的配置文件。例如:如何减少常量中的重复?

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

我想减少“的/ etc/APP1”和“/无功/日志”的重复,但使用的变量不起作用。同样使用先前定义的常量不能在相同的“使用常量块”中工作。例如:

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

不起作用。

使用单独的“使用常量”块可以解决此问题,但会增加大量不需要的代码。

这样做的正确方法是什么?

谢谢。

回答

7

我可能会写这样的:

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; 

然而,这仍然是一个很大的代码,但它确实删除重复数据删除,这是一个双赢。

为什么你的日志文件是数字?如果它们从0开始,则数组是比散列更好的选择。如果他们被命名,他们更具描述性。

+0

感谢您的回答,日志名称并非真正的数字 - 我只是为了这个例子而改变了它们。 – 2008-10-23 09:20:40

3

不幸的是,这并不奏效。原因是你在定义之前使用函数('常数')。您在致电constant->import之前先评估他们。

使用变量不起作用,因为使用语句是在编译时评估的。分配给变量只能在运行时完成,所以它们不会被定义。

我可以给出的唯一解决方案是将其拆分为多个use constant语句。在这种情况下,两个语句将会执行(其中一个用于LOG_DIRCONF_DIR,另一个用于其余的)。

8

使用单独的“使用常量”块 不解决这一问题,但 增加了很多不需要的代码。

这是真的吗?

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

我没有看到很多问题。您只在一个点上指定了基本路径,因此遵守DRY原则。如果您使用环境变量指定BASE_PATH:

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

...你就必须重新配置不变,而无需修改代码的一种廉价的方式。有什么不喜欢这个? “BASE_PATH”

如果你真的想减少重复拼接,你可以加一点机械对自己和因素安装常量远:

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

但在这一点上,我觉得平衡摆脱了正确的讨厌:)首先,你不能再grep的CONF_FILE1,看看它的定义。

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

根据你在做什么,你可能根本不需要常量。大多数情况下,我写的东西是其他人用来完成他们的工作的,所以我解决这个问题的方式可以让其他程序员灵活。我把这些东西变成方法:

sub base_log_dir { '...' } 

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

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

通过这样做,我可以轻松地扩展或覆盖的东西。

虽然这样做会失去持续折叠的价值,所以你必须考虑对你有多重要。