2015-12-04 98 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中做,它會做的。

相關問題