【发布时间】:2016-02-05 18:00:18
【问题描述】:
将运行时所需的数据文件与 Perl 模块捆绑在一起的“正确”方法是什么,以便模块可以在使用之前读取其内容?
一个简单的例子是这个 Dictionary 模块,它需要在启动时读取 (word,definition) 对的列表。
package Reference::Dictionary;
# TODO: This is the Dictionary, which needs to be populated from
# data-file BEFORE calling Lookup!
our %Dictionary;
sub new {
my $class = shift;
return bless {}, $class;
}
sub Lookup {
my ($self,$word) = @_;
return $Dictionary{$word};
}
1;
还有一个驱动程序,Main.pl:
use Reference::Dictionary;
my $dictionary = new Reference::Dictionary;
print $dictionary->Lookup("aardvark");
现在,我的目录结构如下:
root/
Main.pl
Reference/
Dictionary.pm
Dictionary.txt
我似乎无法让 Dictionary.pm 在启动时加载 Dictionary.txt。我已经尝试了一些方法来让它工作,比如......
-
使用 BEGIN 块:
BEGIN { open(FP, '<', 'Dictionary.txt') or die "Can't open: $!\n"; while (<FP>) { chomp; my ($word, $def) = split(/,/); $Dictionary{$word} = $def; } close(FP); }没有骰子:Perl 在 cwd 中查找 Dictionary.txt,它是主脚本 ("Main.pl") 的路径,而不是模块的路径,所以这给出了 File Not Found。
-
使用数据:
BEGIN { while (<DATA>) { chomp; my ($word, $def) = split(/,/); $Dictionary{$word} = $def; } close(DATA); }在模块的末尾
__DATA__ aardvark,an animal which is definitely not an anteater abacus,an oldschool calculator ...这也失败了,因为 BEGIN 在编译时执行,在 DATA 可用之前。
-
对模块中的数据进行硬编码
our %Dictionary = ( aardvark => 'an animal which is definitely not an anteater', abacus => 'an oldschool calculator' ... );有效,但绝对不可维护。
这里有类似的问题:How should I distribute data files with Perl modules?,但该问题处理的是 CPAN 安装的模块,而不是我尝试做的与当前脚本相关的模块。
【问题讨论】:
-
请注意,原型(即
sub new())对方法没有影响。它们不是函数签名,they're something completely different。除非您知道自己在做什么,否则不要使用它们。如果您想要函数签名,请考虑 Method::Signatures、Kavorka 或 Function::Parameters。 -
我建议使用
DATA和INIT而不是BEGIN以确保在运行前初始化数据。它还使它更具自我记录性 -
@Schwern 糟糕,最近 C/C++ 太多了!我将编辑以删除这些。
-
您还应该避免在方法标识符中使用大写字母。它们是为 Perl 全局变量保留的,例如包名,所以你的
sub Lookup应该是sub lookup -
@Borodin 不保留大写方法名称。这不是普通的 Perl 风格,但它们不是保留的。
标签: perl perl-module directory-structure data-files