在使用之前如何检查我是否有Perl模块?

时间:2008-10-30 20:41:59

标签: perl module

我有以下Perl代码,它依赖于Term::ReadKey来获取终端宽度;我的NetBSD版本缺少此模块,因此我希望在模块丢失时将终端的宽度默认为80.

我无法弄清楚如何有条件地使用模块,提前知道它是否可用。我当前的实现只是退出一条消息,说如果它不存在就找不到Term::ReadKey

#/usr/pkg/bin/perl -w
# Try loading Term::ReadKey
use Term::ReadKey;
my ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();
my @p=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97);
my $plen=$#p+1;
printf("num |".("%".int(($wchar-5)/$plen)."d") x $plen."\n",@p);

我在NetBSD上使用Perl 5.8.7,在CygWin上使用5.8.8 你能帮我更有效地将它实现到我的脚本中吗?

8 个答案:

答案 0 :(得分:90)

这是一个不需要其他模块的简单解决方案:

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在运行时解析和编译新代码是没有意义的pair执行相同的操作,并在编译时进行语法检查以启动。)

最后请注意,我在此处使用eval { ... }$@对于此示例而言非常简洁。在实际代码中,您应该使用类似Try::Tiny或至少be aware of the issues it addresses的内容。

答案 1 :(得分:11)

查看CPAN模块Module::Load::Conditional。它会做你想要的。

答案 2 :(得分:7)

经典答案(至少可以追溯到Perl 4,早在'使用'之前)就是'require()'一个模块。这是在脚本运行时执行的,而不是在编译时执行的,您可以测试成功或失败并做出适当的反应。

答案 3 :(得分:4)

如果您需要特定版本的模块:

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) {
    # ...
}

答案 4 :(得分:4)

if  (eval {require Term::ReadKey;1;} ne 1) {
# if module can't load
} else {
Term::ReadKey->import();
}

if  (eval {require Term::ReadKey;1;}) {
#module loaded
Term::ReadKey->import();
}

注意:1;仅在正确加载require Term::...时执行。

答案 5 :(得分:3)

use Module::Load::Conditional qw(check_install);

use if check_install(module => 'Clipboard') != undef, 'Clipboard'; # class methods: paste, copy

使用 if pragma 和 Module::Load::Conditional 核心模块。

check_install 返回 hashref 或 undef


在编译指示文档的 see also 部分也提到了这个模块:

<块引用>

Module::Load::Conditional 提供了许多函数,您可以用来查询哪些模块可用,然后在运行时加载其中一个或多个。

答案 6 :(得分:1)

这是加载可选模块的有效习惯,

use constant HAS_MODULE => defined eval { require Module };

这将需要该模块(如果有),并将状态存储在一个常量中。

您可以这样使用

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;

此方法使用常量。这样做的好处是,如果您没有此模块,则将从optree中清除死代码路径。

答案 7 :(得分:0)

我认为使用变量时它不起作用。 请查看this link,其中说明了如何将其与变量

一起使用
$class = 'Foo::Bar';
        require $class;       # $class is not a bareword
    #or
        require "Foo::Bar";   # not a bareword because of the ""

require函数将查找&#34; Foo :: Bar&#34; @INC数组中的文件,并会抱怨找不到&#34; Foo :: Bar&#34;那里。在这种情况下,你可以这样做:

 eval "require $class";