Как использовать пакет Perl, известный только во время выполнения? - PullRequest
15 голосов
/ 14 января 2009

У меня есть программа на Perl, которая должна использовать пакеты (которые я также пишу). Некоторые из этих пакетов выбираются только во время выполнения (на основе некоторой переменной среды). Конечно, я не хочу вставлять в свой код строку «use» для всех этих пакетов, но только одну строку «use», основанную на этой переменной, что-то вроде:

use $ENV{a};

К сожалению, это не работает, конечно. Есть идеи как это сделать?

Спасибо заранее, Oren

Ответы [ 7 ]

8 голосов
/ 14 января 2009

«use» Операторы запускаются во время компиляции, а не во время выполнения. Вместо этого вам понадобятся ваши модули:

my $module = "Foo::Bar";
eval "require $module";
8 голосов
/ 14 января 2009
eval "require $ENV{a}";

"use" не работает здесь хорошо, потому что он импортирует только в контексте eval.

Как сказал @Manni, на самом деле лучше использовать require. Цитата из man perlfunc:

If EXPR is a bareword, the require assumes a ".pm" extension and 
replaces "::" with "/" in the filename for you, to make it easy to 
load standard modules.  This form of  loading of modules does not 
risk altering your namespace.

In other words, if you try this:

        require Foo::Bar;    # a splendid bareword

The require function will actually look for the "Foo/Bar.pm" file 
in the directories specified in the @INC array.

But if you try this:

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

The require function will look for the "Foo::Bar" file in the @INC 
array and will complain about not finding "Foo::Bar" there.  In this 
case you can do:

        eval "require $class";
6 голосов
/ 14 января 2009

Я бы использовал UNIVERSAL :: require . Он имеет как требуют , так и использовать методы для использования пакета. Метод use также вызовет import для пакета.

use UNIVERSAL::require;
$ENV{a}->use or die 'Could not import package:  ' . $@;
4 голосов
/ 14 января 2009

Я думаю, что модуль, загруженный во время выполнения, может быть плагином. У меня проблема такого рода, когда в некоторых случаях определенные модули загружаются во время выполнения в виде плагинов с Module :: Pluggable .

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

4 голосов
/ 14 января 2009

Возможно, вы захотите использовать require вместо use, если не хотите, чтобы это происходило во время компиляции, а затем вручную импортировать любые символы, которые вам могут понадобиться. См. эту ссылку на Perl Cookbook (из Google Книг) для хорошего обсуждения методов, которые вы можете использовать для достижения желаемого.

3 голосов
/ 05 ноября 2012

Как насчет использования основного модуля Module :: Load

С вашим примером:

use Module::Load;
load $ENV{a};

«Module :: Load - требования времени выполнения как для модулей, так и для файлов»

«загрузка избавляет от необходимости знать, пытаетесь ли вы потребовать файл или модуль.»

Если это не удастся, он умрет с чем-то вроде "Не удается найти xxx в @INC (@INC содержит: ..." .

1 голос
/ 18 августа 2015

Много лет спустя, eval "use $mod_name";, кажется, работает нормально (по крайней мере, на 5.8.8).

Преимущество перед eval "require $mod_name"; состоит в том, что экспортируемые по умолчанию загруженные модули автоматически импортируются; другими словами:

eval "use $mod_name";

является более коротким эквивалентом

eval "require $mod_name"; $mod_name->import();

Вот тестовая команда, которая передает имя модуля через env. переменная mod_name, загружает и импортирует модуль, затем использует импортированную функцию (предполагается, что POSIX-подобная оболочка):

 $ mod_name='Data::Dumper' perl -e 'eval "use $ENV{mod_name}"; print Dumper("hi!")'
 $VAR1 = 'hi!';

Возможно, мне не хватает тонкостей; если да, пожалуйста, дайте мне знать.

...