2010-01-19 53 views
4

我使用一個配置文件(YAML),以定義以後使用的類型來驗證我的應用程序所需的其他配置值:如何將參數傳遞給使用eval定義的Perl子例程?

--- 
action: > 
     use List::MoreUtils; 
     my $value = $_; 
     any { $value eq $_ } qw(fatal keep merge non-fatal replace); 
dir : return defined $_ ? -d $_ : -1; 
file : return defined $_ ? -f $_ : -1; 
string: 1; 


--- 
config-element: 
    value: foo 
    type : file 
etc ... 

的想法是eval每種類型的定義,將其丟入散列,然後調用驗證配置數據(下面是示意性的,易於理解性):

#throw sub refs into hash 
my %type_sub; 
foreach my $key (keys %$type_def_ref) { 
    my $sub_str = "sub {$type_def_ref->{$key}}"; 
    $type_sub{$key} = eval $sub_str; 

} 

#validate (myfile is a real file in the cwd) 
print $type_sub{file}->('myfile'),"\n"; 
print $type_sub{action}->('fatal'), "\n"; 

的問題是,在%type_sub子程序似乎不接受參數。在上述情況下,第一個打印語句輸出-1而第二輸出:

Use of uninitialized value $value in string eq at (eval 15) line 1. 
Use of uninitialized value $_ in string eq at (eval 15) line 1. 
Can't call method "any" without a package or object reference at 
(eval 15) line 1. 

這是不是在所有我所期望的,但在子程序調用。

我在做什麼錯?

編輯: 我正在馬虎,現在一切正常。感謝弗裏多。

回答

3

您的子程序參數將在@_數組中,而不是$_。要獲得第一個參數,請查看$_[0]或執行my $foo = shift;。 (shift默認情況下@_運行。)

至於any,我相信這個問題是由於any不能夠在運行時加載它的原型(子程序原型只能在編譯時被調用。)您可能需要使用明確的parens和明確的子程序引用:

any(sub { $value eq $_ }, qw(fatal keep merge non-fatal replace)); 
+0

哇。我一直使用@_進行移位或列表賦值,並且$ _很常見,我完全忘記了它不會自動設置。 – gvkv 2010-01-19 16:00:21

+0

我剛剛嘗試瞭解'任何'的解決方案,但沒有運氣。這裏有一個更一般的問題,就是如何用eval或其他方法定義一個帶有字符串的子程序。也許我會稍後再問。 – gvkv 2010-01-19 16:05:50

+0

我修好了。 List :: MoreUtils默認不會導出任何東西。 – gvkv 2010-01-19 16:15:33

5

不要在配置中編寫代碼。用代碼創建一個庫,並簡單地配置要使用的子程序名稱。這應該可以爲您節省大量的翻譯字符串的代碼和管理過程。當有人調整配置並引入語法錯誤時,它還可以節省大量的時間追蹤問題。

我在Mastering Perl的「配置」一章以及動態子程序章節中對此進行了廣泛的討論。

代碼不屬於配置。說,直到你相信它。

+0

你當然是對的,但我認爲單線並不是什麼大不了的事情(而且我違反了這個原則)。 – gvkv 2010-01-21 11:12:29

+0

另一個問題是,我不知道如何做到這一點,而不關閉嚴格的裁判。 – gvkv 2010-01-21 12:01:45

相關問題