我正在使用配置文件(在YAML中)来定义稍后用于验证我的应用所需的其他配置值的类型:
---
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中的子程序似乎不接受参数。在上面的例子中,第一个print语句输出-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.
这完全不是我所期望的,但是正在调用子程序。
我做错了什么?
编辑: 我很草率,现在一切正常。感谢弗里多。
答案 0 :(得分:5)
不要在配置中编写代码。使用代码创建一个库,并简单地配置要使用的子例程名称。这应该可以节省大量的工作,将字符串转换为代码并管理流程。当有人调整配置并引入语法错误时,它还可以节省大量时间来跟踪问题。
我在Mastering Perl的“配置”章节以及动态子例程的章节中详细讨论了这一点。
代码不属于配置。说出来,直到你相信它。
答案 1 :(得分:3)
您的子程序参数将位于@_
数组中,而不是$_
。要获取第一个参数,请查看$_[0]
或执行my $foo = shift;
。 (shift
默认情况下会在@_
上运行。)
对于any
,我认为问题是由于any
无法在运行时加载原型(子程序原型只能在编译时调用。)您可能需要使用显式的parens和一个明确的子例程引用:
any( sub { $value eq $_ }, qw(fatal keep merge non-fatal replace) );