Подтвердить что ты не робот

Как использовать пакет Perl, известный только во время выполнения?

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

use $ENV{a};

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

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

4b9b3361

Ответ 1

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";

Ответ 2

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

my $module = "Foo::Bar";
eval "require $module";

Ответ 3

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

use UNIVERSAL::require;
$ENV{a}->use or die 'Could not import package:  ' . [email protected];

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

В вашем примере:

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

"Модуль:: Загрузка - время выполнения как модулей, так и файлов"

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

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

Ответ 7

Спустя много лет 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!';

Возможно, мне недостает тонкостей; если да, сообщите мне.