2008-10-30 2 views
41

У меня есть следующий код Perl, который полагается на Term::ReadKey, чтобы получить ширину терминала; В моей сборке NetBSD отсутствует этот модуль, поэтому я хочу по умолчанию использовать ширину терминала до 80, когда модуль отсутствует.Как проверить, есть ли у меня модуль Perl перед его использованием?

Я не могу понять, как условно использовать модуль, зная заранее, доступен ли он. Моя текущая реализация просто завершается с сообщением о том, что он не может найти 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); 

Я использую Perl 5.8.7 на NetBSD и 5.8.8 на CygWin Можете ли вы помочь мне осуществить это в мой сценарий, более эффективно?

+3

На мой взгляд, либо название неправильно, или все ответы (за исключением, возможно, один с помощью модуля :: Load :: Условный, если check_install() используется) неверны ,Заголовок спрашивает, как проверить «если у меня есть модуль Perl * перед его использованием». Во всех ответах используется несколько вариантов «обнаружения ошибок с eval * while», требующих/загрузки/использования ». – 2014-05-12 13:37:43

ответ

79

Вот скелетное решение, которое не требует другого модуля:

my $rc = eval 
{ 
    require Term::ReadKey; 
    Term::ReadKey->import(); 
    1; 
}; 

if($rc) 
{ 
    # Term::ReadKey loaded and imported successfully 
    ... 
} 

Обратите внимание, что все ответы ниже (я надеюсь, что они ниже этого один :-), что использование eval { use SomeModule } неправы, потому что use операторы оцениваются во время компиляции независимо от того, где они находятся в коде. Поэтому, если SomeModule недоступен, скрипт сразу же умрет при компиляции.

(Строка Eval из use заявления также будет работать (eval 'use SomeModule';), но нет никакого смысла синтаксического анализа и компиляции нового кода во время выполнения, когда пара require/import делает то же самое, и синтаксис проверяются во время компиляции boot.)

Наконец, обратите внимание, что мое использование eval { ... } и [email protected] здесь кратким для этого примера. В реальном коде вы должны использовать что-то вроде Try::Tiny или не менее be aware of the issues it addresses.

10

Проверьте модуль CPAN Module::Load::Conditional. Он будет делать то, что вы хотите.

+5

Конечно, это работает, только если у вас есть тот, который установлен. Наверное, лучшее решение, если вы это сделаете. – tvanfosson 2008-10-30 20:57:27

+0

Да ... Я не могу гарантировать, что у меня есть этот. И хотя Detect :: Module есть, он не перечисляет все модули в списке $ installed-> modules(), возвращаемом именами модулей. – dlamblin 2008-10-30 21:03:13

6

Классический ответ (начиная с Perl 4, по крайней мере, задолго до того, как был «использование») был «требовать()» модуля. Это выполняется, когда скрипт запускается, а не компилируется, и вы можете проверить успех или неудачу и отреагировать соответствующим образом.

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
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::... загружен правильно.

0

Я думаю, что это не работает при использовании переменных. Пожалуйста, проверьте this link, который объясняет, как он может быть использован с переменной

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

Требовать функция будет искать файл «Foo :: Bar» в массиве @INC и будет жаловаться не найти «Foo :: Bar " там. В этом случае вы можете сделать:

eval "require $class";