2015-12-04 58 views
0

加载我目前有一堆Perl代码,其中包含类似于导出大量其他模块正在使用的变量的configuration.pm文件。同一模块至少使用一个模块,将其称为Foo,我们在配置中提供的一些辅助方法中编写了它(它们应该位于不同的模块中,但尚未准备好进行更改)。允许更改位置perl模块使用配置参数

目前,它加载模块像靠近文件顶部这一权利:

Begin{ push @INC, 'hard/coded/directory'} 
use Module::Foo; 

我试图摆脱这种硬编码目录。我已经添加了一个默认配置文件来从中读取数据。我搬到进口了一些,取而代之的是一个要求,像这样使用...

$script_directory = $config_data_from_file{'script_directory'}; 
push @inc, $script_directory; 
require Module::Foo; 

不过,我想添加一个命令行参数Main.pl如果我指向一个不同的配置文件不想使用默认的。我的问题是,所有其他模块希望配置.pm一旦包含配置数据和所需的foo。所以我不能有configuration.pm等待初始化,直到main.pl准备就绪。我可以拿出最接近的是这样的:

package Configuration; 

load_config_file('default/file/location'); 

sub load_config_file($){ 

    $config_data_from_file = read_file(@_[0]); 

    $script_directory = $config_data_from_file{'script_directory'}; 
    push @inc, $script_directory; 
    require Module::Foo; 

    #load the rest 
} 

,并有Main.pl召回load_config_file如果命令行选项更改配置文件。

但这是一个问题,有两个原因。首先,如果我的默认脚本位置不存在,当我尝试执行第一次导入时,仍会爆炸。其次,我需要两次Foo,覆盖它,如果文件之间存在差异,可能会导致问题。为此,应该避免将默认script_directory添加到@INC。

有几种方法可以解决我能看到的问题。一种更加干净地加载不同版本的模块以替换旧版本的方法,一种使Foo延迟加载的方式,直到它第一次在文件中使用它,或者一种方法来延迟$ load_config_file方法,直到我读取例如配置文件。然而,作为perl的新手,我不知道如何去做任何一个,也没有太多的运气来发现如何在线。

我现在实际上可以做到这一点,加载数据的一个脆弱的顺序,通过重构几十个脚本来更快地实现长期解决方案(但我很害怕触及)在我有办法测试我的计算机上的代码之前,有很多代码)。然而,我想部分地希望学习更多Perl的功能,后面我可能会发现它有用;如果我不能进行重构,这将如何解决?

回答

2

如果你想给的配置文件,你可以做这样的事情的第一个参数:

主要脚本:

#!perl 

    BEGIN { 
    use Configuration; 
    } 

    use Module::Foo; 
    ... rest of script ... 

Configuration.pm:

package Configuration; 

    load_config_file($ARGV[0] || 'default/file/location'); 

    sub load_config_file($){ 

    $config_data_from_file = read_file(@_[0]); 

    $script_directory = $config_data_from_file; 
    push @INC, $script_directory; 

    } 
0

我的解决办法通常是在我的配置文件中查找配置文件的-f参数,并在可能的情况下加载配置文件,然后离开@ARGV变量一触即发,让其他人仍然可以解析它。这意味着我们最终解析命令行参数两次(实际上是3次),但这并没有造成任何实际的伤害。我强制执行在使用我的配置的任何模块中预定义的-f参数。pm,并且需要configuration.pm作为我们包含的第一个模块,但我认为这是一个小的开销。任何使用我们的configuration.pm文件进行配置参数的人都应该要求这种行为。

我发现AppConfig是处理这个问题的最佳模块。我的解决方案可以在没有它的情况下完成,但是AppConfig使它更加清洁,因为它结合了从配置文件和命令行加载变量的方式。事实上,我纯粹意外地加入了从命令行直接修改任何单个变量的能力,只要他们选择了我所做的方式。

我configuration.pm看起来像命中(从内存改写这个,不准确)

$conf = AppConfig -> new({ 
      GLOBAL=> { 
       EXPAND => AppConfig::Expand_Var, 
       ARGCOUNT => AppConfig::ARGCOUNT_ONE 
     }}) 

$conf.define("script_dir", {DEFAULT = "/default/location"}); 
$conf->define("f", {ALIAS ="file|conf_file"}); 
...other defines here 

#read config file if -f arg exists 
parse_commandline_args(); 
$conf->file($conf->conf_file()) if defined $conf->conf_file() 

#reread command line so that arguments on it override those in conf file 
parse_commandline_args(); 

#at this point script_dir should be correct so safely include it. 
push @INC $conf->script_dir(); 

sub parse_commandline_args(){ 

    $copy_of_args = [@ARGV]; 
    $conf->args($copy_of_args); 
} 

我main.pl几乎不变。我在模块顶部附近使用configuration.pm,其他所有内容都正常工作。我仍然需要通过并重新定义所有使用脚本来需要它的脚本,以便configuration.pm有时间在它运行之前更新INC,但除此之外,其余部分正常工作。无论我想使用配置文件中的内容,我现在只需$ conf-> variable()

parse_commandline_args很重要。只需使用$ conf-> args()就可以清除@ARGV的内容,使它们不能用于以后的模块,比如我的main.pl。通过首先复制数组,我们保留原始的@ARGV,以备后用。

不知道我是否会推荐这从无到有,感觉错configuration.pm的方式是自动做的一切,但对于更新我们的丑陋原型足够长的时间来维护它,直到被资助编写适当多个版本的功能,我不会在perl中做,它会做的。

相关问题