2016-10-14 10 views
1

Есть ли способ сообщить о недостающих модулях, используемых в файле Perl, заранее, а не получать как ошибку.Проверьте и сообщите, что модуль модуля Perl отсутствует

У меня есть что-то вроде use Digest::MD5, use File::DosGlob модулей в моей программе на Perl. Всякий раз, когда пользователи запускают скрипт, они получают ошибку, если в их системе нет определенного модуля. Они не могли понять сообщение об ошибке по умолчанию, указанное @INC. Поэтому я хотел бы четко сказать им, что эти модули необходимо установить для запуска скрипта.

ответ

5

Вы можете создать собственную проверку, используя a BEGIN block. Они запускаются во время компиляции, как и use. Имейте в виду, что use Foo не по существу ничто иное, как это:

BEGIN { 
    require Foo; 
    Foo->import; 
} 

Следующий код заменит все use заявления с одним BEGIN и поместить их внутри eval. Это по существу похоже на механизм try/catch.

Нам нужна строка eval (которая считается злом здесь), потому что require только преобразует из имен пакетов с двоеточием :: к путям, если аргумент a bareword. Но поскольку у нас есть имя в $module, это строка, поэтому нам нужно поместить ее в eval согласно require's docs.

Если эта строка eval не работает, мы die. Это поймано внешним блоком eval и установлено [email protected]. Затем мы можем проверить, содержит ли оно наше имя модуля, и в этом случае мы наивно предполагаем, что сбой был вызван тем, что этот модуль не установлен. Эта проверка может быть немного более сложной.

Мы отслеживаем любые сбои в $fails, и если они были, остановимся.

#!/usr/bin/perl 
use strict; 
use warnings; 

# all our use statements go here 
BEGIN { 
    my $fails; 
    foreach my $module (qw/Digest::MD5 File::DosGlob ASDF/) { 
     eval { 
      eval "require $module" or die; # because $module is not a bareword 
      $module->import; 
     }; 
     if ([email protected] && [email protected] =~ /$module/) { 
      warn "You need to install the $module module"; 
      $fails++; 
     } 
    } 
    exit if $fails; 
} 

# ... 

Выше я включил ASDF, что у меня нет, поэтому при запуске он будет говорить

Вам необходимо установить модуль ASDF на /home/code/scratch.pl линии 1335.

Возможно, вы захотите сделать это сообщение более подробным. Если ваши пользователи не могут понять сообщение об ошибке по умолчанию, которое Perl дает, когда он не может найти модуль, возможно, было бы разумно включить руководство по установке материалов прямо там.

Обратите внимание, что оба модуля, которые вы указали, были включены в Perl для a while (читать: с марта 2002 года). Итак, почему вы хотите сделать это для этих модулей?

$ corelist Digest::MD5 

Data for 2014-09-14 
Digest::MD5 was first released with perl v5.7.3 

$ corelist File::DosGlob 

Data for 2014-09-14 
File::DosGlob was first released with perl 5.00405 

Лучше всего было бы отправить вашу программу в качестве распределения, который может быть установлен, и включают в Makefile или cpanfile или что-то подобное, в котором перечислены зависимости. Существует руководство в perlnewmod о том, как запустить новый модуль. Вы не хотите загружать в CPAN, очевидно, но основы одинаковы.

При этом ваши пользователи будут автоматически устанавливать все зависимости.

+0

Спасибо, что упомянул _perlnewmod_. Я всегда задавался вопросом, как CPAN заселяется. – PerlDuck

+0

Существует намного больше, чем просто doc @PerlDuck. Существуют различные инструменты для запуска новых дистрибутивов, а также несколько руководств. Возможно, сейчас самое подходящее время для выпуска чего-то на CPAN. Пойдите, сделайте учетную запись PAUSE. :) – simbabque

+0

Я действительно не знаком с makefile или cpanfile, Begin работает для одного файла. Спасибо за это, но если я хочу проверить все файлы perl в папке, как это можно сделать – VSr

1

В вашем вопросе не совсем ясно, что означает «заранее». Чтобы проверить синтаксис Perl программы, является правильным и непосредственно включены модули разрешимы, используйте

perl -c <perl-program.pl> 

Это проверяет синтаксис файла и гарантирует, что любые модули use дней вашего коду существуют. Однако он не проводит транзитного контроля всего дерева зависимостей, только те, которые указаны в perl-program.pl.

+2

Если вы имеете в виду модули 'use'd в модулях, которые использует ваш код, то да, это так. То, что он не может сделать, это проверить модули, предназначенные для загрузки во время выполнения, используя 'require'. – mbethke

+1

Если 'test1.pl' использует' test2.pm' в том же каталоге, а 'test2.pm' имеет плохой' use', он будет пойман только с расширением 'perl -c test2.pm', а не' perl -c test1.pl' –

+0

Работает для меня с perl 5.24, и я уверен, что это всегда было так. '$ echo" использовать X; " > X.pl; echo "пакет X, используйте Y;" > X.pm; perl -c x.pl' приводит к 'Не удается найти Y.pm в @ INC' – mbethke

5

Вы можете использовать Devel::Modlist, он перечислит весь необходимый модуль для вашей программы.

perl -d:Modlist test.pl 

Там еще один модуль Module::ScanDeps, который поставляется с утилитой scandeps.pl которые вы можете использовать на вашем сценарии как:

scandeps.pl test.pl 

Обратите внимание, что sanity checking your Perl code using perl -c is dangerous, так тщательно использовать.