如果安装了可选的Perl模块,我如何要求它?
我有Perl代码,它依赖于如果安装了可选的Perl模块,我如何要求它?,perl,module,require,Perl,Module,Require,我有Perl代码,它依赖于Term::ReadKey来获取终端宽度。我的安装缺少此模块,因此如果该模块不存在,我希望提供默认设置,而不是引发异常 如何有条件地使用可选模块,而不提前知道它是否可用 # but only if the module is installed and exists use Term::ReadKey; ... 如何实现这一点?查看CPAN模块。它可以满足您的需要。这里有一个基本的解决方案,不需要其他模块: my $rc = eval { require Term
Term::ReadKey
来获取终端宽度。我的安装缺少此模块,因此如果该模块不存在,我希望提供默认设置,而不是引发异常
如何有条件地使用可选模块,而不提前知道它是否可用
# but only if the module is installed and exists
use Term::ReadKey;
...
如何实现这一点?查看CPAN模块。它可以满足您的需要。这里有一个基本的解决方案,不需要其他模块:
my $rc = eval
{
require Term::ReadKey;
Term::ReadKey->import();
1;
};
if($rc)
{
# Term::ReadKey loaded and imported successfully
...
}
请注意,下面使用eval{use SomeModule}
的所有答案(我希望它们在下面!:-)都是错误的,因为use
语句在编译时进行计算,而不管它们出现在代码中的何处。因此,如果SomeModule
不可用,脚本将在编译后立即失效
(一个use
语句的字符串eval也会起作用(eval'use SomeModule';
),但是当require
/import
对执行同样的操作时,在运行时解析和编译新代码没有意义,并且在编译时检查语法以引导。)
最后,请注意,为了本例的目的,我在这里使用的
eval{…}
和$@
非常简洁。在实际代码中,您应该使用类似或至少类似的方法。经典答案(至少可以追溯到Perl 4,在“使用”之前很久)是“require()”模块。这是在脚本运行时执行的,而不是在编译时执行的,您可以测试成功或失败,并做出适当的反应。如果您需要特定版本的模块:
my $GOT_READKEY;
BEGIN {
eval {
require Term::ReadKey;
Term::ReadKey->import();
$GOT_READKEY = 1 if $Term::ReadKey::VERSION >= 2.30;
};
}
# elsewhere in the code
if ($GOT_READKEY) {
# ...
}
或
注:
1代码>仅在正确加载require Term::…
时执行。我认为在使用变量时它不起作用。
请检查说明如何将其与变量一起使用的内容
$class = 'Foo::Bar';
require $class; # $class is not a bareword
#or
require "Foo::Bar"; # not a bareword because of the ""
require函数将在@INC数组中查找“Foo::Bar”文件,并会抱怨没有在那里找到“Foo::Bar”。在这种情况下,您可以执行以下操作:
eval "require $class";
这是加载可选模块()的有效习惯用法
这将需要模块(如果可用),并将状态存储在常量中
你可以这样使用它
use constant HAS_READLINE => defined eval { require Term::ReadKey };
my $width = 80;
if ( HAS_READLINE ) {
$width = # ... code, override default.
}
注意,如果您需要导入它并引入符号,您也可以轻松地进行导入。你可以跟进
use constant HAS_READLINE => defined eval { require Term::ReadKey };
Term::ReadKey->import if HAS_READLINE;
此方法使用常量。这样做的好处是,如果没有此模块,则会从操作树中清除死代码路径
use Module::Load::Conditional qw(check_install);
use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy
使用pragma和核心模块
返回hashref或undef
pragma文档的一节中也提到了该模块:
Module::Load::Conditional提供了许多函数,您可以使用这些函数查询可用的模块,然后在运行时加载其中一个或多个模块
当然,只有在你也安装了这个的情况下,这才有效。如果你这样做的话,可能是更好的解决方案。是的。。。我不能保证我有那个。虽然Detect::Module是,但它并没有列出它的$installed->modules()返回的模块名列表中的所有模块。哦,我应该先想到这一点+1是的,这确实有效,并且eval块后的分号非常重要。尽可能避免依赖$@。例如,一些模块在加载时可以将$@设置为副作用,而不会实际引发异常。更好的选择是依赖这样一个事实,eval
在捕获异常时将返回undef,即if(eval“use Term::ReadKey”){…}
。如果模块(或任何其他内容)在生成异常后执行eval(例如,在SIGDIE处理程序或销毁方法中),$@的值将替换为最新评估的结果。use Term::ReadKey代码>和eval{require Term::ReadKey}答案中的code>是现在Term::ReadKey
在BEGIN
块中不可用。但在OP的例子中,这不是问题。在我看来,要么标题是错误的,要么所有答案(如果使用check_install()的话,可能除了使用Module::Load::Conditional的答案)都是错误的。标题询问如何检查“在使用前是否有Perl模块”。所有的答案都使用“EVE检测错误,同时要求/加载/使用它”的一些变体。我考虑不同的加载和使用。你可能不同意…Perl关键字有一个非常具体的含义,因此我认为动词“使用”有类似的特定含义。我不确定“加载”指的是什么。。。所以是的,我想我们会同意不同意;-)@EvanCarroll您的答案很好,尽管它在功能上与所选答案相同。但是否有必要改变这个问题?如果我在谷歌上搜索“如何在Perl中在使用模块之前检查模块”,我不太可能搜索“如何在Perl中选择模块”。我认为显示我默认的模块中的内容有助于获得严肃的答案,而不是“为什么?”的评论。@EvanCarroll我理解有时候你会有一个问题,它会作为现有问题的副本关闭。发生的次数比它应该发生的要多。这并不意味着我的问题“不是问题”。你应该与评审员讨论,或者在这里添加你的答案,注意这是一种替代框架。我真希望有一种更简单、噪音更小的方法,使用内置的use
指令。
use constant HAS_READLINE => defined eval { require Term::ReadKey };
my $width = 80;
if ( HAS_READLINE ) {
$width = # ... code, override default.
}
use constant HAS_READLINE => defined eval { require Term::ReadKey };
Term::ReadKey->import if HAS_READLINE;
use Module::Load::Conditional qw(check_install);
use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy