如何使用 Perl 作为配置文件的语言?

How to use Perl as a language for a configuration file?

我有一个允许用户在 Perl 中指定配置文件的应用程序。

我的想法类似于 PKGBUILD 在 Arch 中的使用方式:它是一个 Bash 脚本,它只是来自 "makepkg" 工具的 sourced。它包含变量和函数定义:

pkgbase=somepkg
pkgname=('somepkg')
pkgver=0.0.1
...
prepare() {
    cd "${srcdir}/${pkgbase}-${pkgver}"
    ...
}

我想在 Perl 中做这样的事情。我想我正在寻找 source 的 Perl 版本,它可以读取文件、对其求值并将所有子例程和变量导入调用者的命名空间。使用 Bash 版本,我可以想象编写一个 PKGBUILD,它获取另一个 PKGBUILD,然后覆盖一个或两个变量;我希望这种 "inheritance" 也可以出现在我的 Perl 配置文件中。

Perl 的 do 的一个问题是它似乎将文件的变量和子例程放入单独的名称空间中。另外,我不知道如何覆盖真正的子程序,只命名匿名子程序。

这里有一个版本可以用来说明我想做什么。它不是很优雅,但它演示了覆盖子例程和变量,以及调用先前定义的子例程:

$ cat test-override
#!/usr/bin/perl

use warnings;
use strict;

my @tables = qw(a b c);

my $print_tables = sub {
   print join(", ", @tables), "\n";
};

eval(`cat "test-conf"`) or die "$@";

&$print_tables();

$ cat test-conf
@tables = qw(d e f);

my $old_print_tables = $print_tables;
$print_tables = sub {
  warn "In test-conf $print_tables\n";
  &$old_print_tables();
}

$ ./test-override
In test-conf $print_tables
d, e, f

另一种方法是让配置文件return 成为一个散列,以数据和子例程作为值。还有使用 类 和继承的选项。但是,我希望配置文件在语法上尽可能轻量。

"do"的文档提到了在配置文件中使用 Perl 的可能性,所以我知道这个问题之前已经考虑过了。是否有一个规范的例子说明如何以 "user-friendly" 方式进行操作?

你对你想要这个 "configuration file" 做什么的描述(将 subs 和变量导入调用者的命名空间,覆盖 subs,类,继承......)听起来像一个标准的 Perl 模块.所以使用标准的 Perl 模块。

请注意,此方法有广泛的先例:标准 cpan 命令行客户端将其配置存储在一个模块中,该模块位于 *nix 类型系统上的默认路径 ~/.cpan/CPAN/MyConfig.pm .诚然,cpanMyConfig.pm 是一个非常简单的示例,它只是设置 hashref $CPAN::Config,但没有理由它不能同时完成任何模块所做的所有其他事情。

但是用 do 做起来很简单。我怀疑你只是想多了:

$ cat test-override 
#!/usr/bin/perl

use warnings;
use strict;

our @tables = qw(a b c);

sub print_tables {
   print join(", ", @tables), "\n";
};

print_tables;

do "test-conf";

print_tables;

print "\@tables is @tables\n";

$ cat test-conf 
@tables = qw(d e f);

sub print_tables {
  print "print_tables from test_conf\n";
}

$ ./test-override 
a, b, c
print_tables from test_conf
@tables is d e f

我对 @tables 所做的重要更改是将其从 my 更改为仅在当前范围 和当前文件 内可见,到 our,它在同一个包内的任何地方都可见(如果包名称限定,则从其他包可见)。

但是我的配置文件中的 print_tables 没有调用原来的 print_tables,你只是运气不好。因为只能有一个&main::print_tables,替换掉会完全覆盖原来的,原来的已经不存在了。如果您希望能够覆盖它并且仍然能够调用原始文件,则需要将两个声明放入不同的包中,这意味着使用 OO Perl(这样您就可以多态调用正确的).

另请注意,usemy 具有相同的词法范围,这意味着您的 use strict; use warnings; 不会 进入配置文件。您可以通过在我的 test-conf 版本中添加 use warnings; 来轻松演示这一点,此时它将生成警告 Subroutine print_tables redefined.