我发现以下反模式在我的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模块来解决这个问题?为什么?
解决方法
我最喜欢的是
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'
- ];