我发现在我的Perl脚本中重复了以下反模式:脚本包含一些特定于机器/设置的设置,我将其作为常量存储在脚本中,而脚本的其余部分本质上是通用的:
#!/usr/bin/perl
use strict;
use warnings;
# machine specific settings at the start of the script.
my $SETTING_1 = "foo";
my @SETTING_2 = ("123", "456");
my $SETTING_3 = "something";
# general part of script follows.
...
当在一台机器上运行时,这种模式有点好,但是一旦我想将脚本分发到多台机器,麻烦就开始了,因为我必须跟踪,以便我不会用一般的新更新覆盖设置部分一部分。
正确的解决方案显然是拥有一个通用脚本文件,并让它读取一个特定于脚本运行环境的配置文件。
我的问题是:您建议使用哪种CPAN模块来解决此问题?为什么呢?
答案 0 :(得分:7)
对于配置文件,我喜欢使用YAML。简单,跨平台,人类可读,并且没有您的配置意外变形为实际程序的危险。
答案 1 :(得分:4)
我最喜欢的是Config::Std。我喜欢它处理multi-line和multi-part配置值的方式。
当变量可能多值时,您必须小心:如果配置文件中存在单个值,它将以标量存储该值;如果存在多个值,您将获得一个数组引用。
我发现有两个配置文件很方便:一个用于描述操作环境的值(在哪里可以找到库等),另一个用于用户可修改的行为。
我也想写一个包装器。例如(更新为包含自动生成的只读访问器):
#!/usr/bin/perl
package My::Config;
use strict; use warnings;
use Config::Std;
use FindBin qw($Bin);
use File::Spec::Functions qw( catfile );
sub new {
my $class = shift;
my ($config_file) = @_;
$config_file = catfile($Bin, 'config.ini');
read_config $config_file => my %config;
my $object = bless \%config => $class;
$object->gen_accessors(
single => {
install => [ qw( root ) ],
},
multi => {
template => [ qw( dir ) ],
},
);
return $object;
}
sub gen_accessors {
my $config = shift;
my %args = @_;
my $class = ref $config;
{
no strict 'refs';
for my $section ( keys %{ $args{single} } ) {
my @vars = @{ $args{single}->{$section} };
for my $var ( @vars ) {
*{ "${class}::${section}_${var}" } = sub {
$config->{$section}{$var};
};
}
}
for my $section ( keys %{ $args{multi} } ) {
my @vars = @{ $args{multi}->{$section} };
for my $var ( @vars ) {
*{ "${class}::${section}_${var}" } = sub {
my $val = $config->{$section}{$var};
return [ $val ] unless 'ARRAY' eq ref $val;
return $val;
}
}
}
}
return;
}
package main;
use strict; use warnings;
my $config = My::Config->new;
use Data::Dumper;
print Dumper($config->install_root, $config->template_dir);
C:\Temp> cat config.ini [install] root = c:\opt [template] dir = C:\opt\app\tmpl dir = C:\opt\common\tmpl
输出:
C:\Temp> g.pl $VAR1 = 'c:\\opt'; $VAR2 = [ 'C:\\opt\\app\\tmpl', 'C:\\opt\\common\\tmpl' ];
答案 2 :(得分:2)
我更喜欢YAML和YAML::XS配置数据。它简单易读,并且几乎可以与任何编程语言绑定。另一个受欢迎的选择是Config::General。
答案 3 :(得分:2)
Config:Properties库适用于读取和写入键/值对属性文件。
答案 4 :(得分:1)
通常的低技术方法是简单地do EXPR配置文件。你看过这个吗?
答案 5 :(得分:1)
冒着被淘汰的风险,一种解决方案是将配置存储在XML中(或者用于更冒险的JSON)。 Perl之外的人为可互操作的,不必在本地PC上运行(可以从“配置URL”请求XML和JSON)和一堆标准模块(XML :: Simple通常足够用于CPAN上存在配置XML文件。
答案 6 :(得分:1)
对于这样的简单配置,特别是对于我不希望在现实世界中改变这些数据的琐碎事情,我经常只使用YAML。简单是不可能的:
首先,编写包含配置的Perl数据结构。
use YAML;
my $SETTINGS = {
'1' => "foo",
'2' => ["123", "456"],
'3' => "something",
};
然后,将其传递给YAML :: DumpFile();
YAML::DumpFile("~/.$appname.yaml", $SETTINGS);
删除数据结构并将其替换为
my $SETTINGS = YAML::LoadFile("~/.$appname.yaml");
然后忘掉它。即使您不知道或不想学习YAML语法,也可以手动对配置进行细微更改,可以在Perl中完成更多主要更改,然后重新转储到YAML。
答案 7 :(得分:0)
不要将自己绑定到格式 - 使用Config::Any,或者使用更多的whizbang DWIM因子Config::JFDI(它本身包含Config :: Any)。通过它们,您可以自己购买支持INI,YAML,XML,Apache-style config等功能。
Config :: JFDI通过尝试捕获Catalyst的配置加载器的一些神奇功能来构建:将实例本地配置与app-wide配置,环境变量支持和有限的宏设施合并(__path_to(foo/bar)__
经常出人意料地派上用场。)