将运行时所需的数据文件与 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 {
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 在编译时执行,在 之前数据 可用。
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 安装的模块,而不是我试图做的与当前脚本相关的模块。
最佳答案
无需在 BEGIN
加载字典时间。 BEGIN
时间是相对于正在加载的文件的。当您的 main.pl
说use Dictionary
,Dictionary.pm 中的所有代码都被编译和加载。将代码提前加载到 Dictionary.pm 中。
package Dictionary;
use strict;
use warnings;
my %Dictionary; # There is no need for a global
while (<DATA>) {
chomp;
my ($word, $def) = split(/,/);
$Dictionary{$word} = $def;
}
您也可以从
Dictionary.txt
加载位于同一目录中。诀窍是您必须提供文件的绝对路径。您可以从 __FILE__
获取此信息这是当前文件的路径(即 Dictionary.pm
)。use File::Basename;
# Get the directory Dictionary.pm is located in.
my $dir = dirname(__FILE__);
open(my $fh, '<', "$dir/Dictionary.txt") or die "Can't open: $!\n";
my %Dictionary;
while (<$fh>) {
chomp;
my ($word, $def) = split(/,/);
$Dictionary{$word} = $def;
}
close($fh);
你应该使用哪个?
DATA
更容易分发。非编码人员更容易处理单独的并行文件。比在加载库时加载整个字典要好,在需要时等待加载它更礼貌。
use File::Basename;
# Load the dictionary from Dictionary.txt
sub _load_dictionary {
my %dictionary;
# Get the directory Dictionary.pm is located in.
my $dir = dirname(__FILE__);
open(my $fh, '<', "$dir/Dictionary.txt") or die "Can't open: $!\n";
while (<$fh>) {
chomp;
my ($word, $def) = split(/,/);
$dictionary{$word} = $def;
}
return \%dictionary;
}
# Get the possibly cached dictionary
my $Dictionary;
sub _get_dictionary {
return $Dictionary ||= _load_dictionary;
}
sub new {
my $class = shift;
my $self = bless {}, $class;
$self->{dictionary} = $self->_get_dictionary;
return $self;
}
sub lookup {
my $self = shift;
my $word = shift;
return $self->{dictionary}{$word};
}
现在,每个对象都包含对共享字典的引用(无需全局),该字典仅在创建对象时加载。
关于perl - 如何在 Perl 模块中包含数据文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33535453/