如何使用 Perl 作为配置文件的语言?
How to use Perl as a language for a configuration file?
我有一个允许用户在 Perl 中指定配置文件的应用程序。
我的想法类似于 PKGBUILD 在 Arch 中的使用方式:它是一个 Bash 脚本,它只是来自 "makepkg" 工具的 source
d。它包含变量和函数定义:
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
.诚然,cpan
的 MyConfig.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(这样您就可以多态调用正确的).
另请注意,use
与 my
具有相同的词法范围,这意味着您的 use strict; use warnings;
不会 进入配置文件。您可以通过在我的 test-conf
版本中添加 use warnings;
来轻松演示这一点,此时它将生成警告 Subroutine print_tables redefined
.
我有一个允许用户在 Perl 中指定配置文件的应用程序。
我的想法类似于 PKGBUILD 在 Arch 中的使用方式:它是一个 Bash 脚本,它只是来自 "makepkg" 工具的 source
d。它包含变量和函数定义:
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
.诚然,cpan
的 MyConfig.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(这样您就可以多态调用正确的).
另请注意,use
与 my
具有相同的词法范围,这意味着您的 use strict; use warnings;
不会 进入配置文件。您可以通过在我的 test-conf
版本中添加 use warnings;
来轻松演示这一点,此时它将生成警告 Subroutine print_tables redefined
.