如果Perl是严格的动态语言,您可以轻松地检查程序中是否安装了模块。问题在于Perl并不是100%动态的。它会进行一些编译工作,并且在检查模块之后完成部分编译工作。
Bulrush的想法是正确的。不幸的是,您无法使用use
子句来实现此目的。 use
在预编译时进行检查,因此您将在eval
执行之前收到错误。
然而,在use perldoc页面中有一个提示:
- use Module LIST
- use Module
- use VERSION
从命名模块中向当前包导入一些语义,通常通过将某些子例程或变量名称别名到您的包中来实现。它与以下内容完全等效
BEGIN { require Module; Module->import( LIST ); }
好了!你可以在BEGIN子句中使用require
,该子句甚至在文件的其余部分被解析之前就已执行。你也可以在那里使用eval
来查看是否有效。由于作用域问题,你需要使用一个包变量作为标志来查看是否有效。普通的词法作用域变量将在离开BEGIN
子句时消失。
BEGIN {
our $FOO_BAR_available = 0;
eval {
require Foo::Bar;
Module->import( qw(...) );
};
if (not $@ ) {
$FOO_BAR_AVAILABLE = 0;
}
}
然后在你的程序中,你会有:
our $FOO_BAR_available;
if ( not $FOO_BAR_available ) {
}
else {
}
our $FOO_BAR_available
有点令人困惑。你并没有重新声明这个变量,只是声明你想要使用这个变量而不用前缀全包名。该变量在 BEGIN
子句中设置,这不会影响其值。
如果该模块被编写得正确,则可以完全跳过使用包变量。模块应该设置一个名为 $VERSION
的包变量。您可以将此变量用作标志:
BEGIN {
eval {
require Foo::Bar;
Module->import( qw(...) ); # No need if you don't import any subroutines
};
}
请注意,我不仅不必声明包变量,甚至不必验证eval
语句是否成功。
然后在您的程序中...
if ( not $FOO::BAR::VERSION ) {
}
else {
}
如果模块设置了$VERSION
变量,那么你就知道它已被加载。否则,你就知道该模块未被加载。
附录
我想在将代码部署到生产环境之前检查它,以避免出现任何错误。这个例子在生产环境中会失败,我希望在那之前捕获错误,例如当我运行单元测试时。
以下是我的建议。虽然不像运行脚本那么简单,但效果要好得多:
通常情况下,您不会在生产环境中运行flake8
。那时,为时已晚。
Perl有很多好用的工具可以执行类似的功能:
- Perlbrew:这允许您的开发人员在其开发系统中安装一个单独的Perl程序和它自己的CPAN模块库。他们可以使用这个来匹配Perl版本和所需的模块到生产环境。这样,他们就是按照相同的规则进行操作。
- Perlcritic:这检查您的模块是否符合Damian Conway在他的Perl最佳实践中制定的编码标准。
- B::Lint:这就像C语言中旧的
lint
程序,可以捕获编码问题。
然而,这些都是在您准备好在生产环境中运行之前要做的事情。使用Vagrant帮助开发人员设置自己的私有生产环境进行测试。使用Jenkins确保您在非常类似于生产环境的环境中进行测试,并尽早捕获错误,而不是在UAT测试之后。
*{'Foo::Buzz::'}{HASH}
来检查是否已加载Foo::Buzz
,这是Foo::Buzz
的存储区。但是,除非你满意于一种简单的方法,只需在代码中查找所有Xxx::Yyy
等内容,否则枚举使用的包远非简单。 - Borodin