Есть ли способ "использовать" один файл, который, в свою очередь, использует несколько других в Perl?
Я хотел бы создать несколько модулей, которые будут использоваться почти во всех сценариях и модулях моего проекта. Это может быть использовать d в каждом из моих скриптов:
#!/usr/bin/perl
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
# Potentially many more.
Можно ли переместить все эти операторы use в новый модуль Foo::Corge
, а затем только use Foo::Corge
в каждом из моих сценариев и модулей?
Ответы
Ответ 1
Что-то вроде этого должно работать:
http://mail.pm.org/pipermail/chicago-talk/2008-March/004829.html
В принципе, создайте свой пакет с большим количеством модулей:
package Lots::Of::Modules;
use strict; # strictly optional, really
# These are the modules we want everywhere we say "use Lots::Of::Modules".
# Any exports are re-imported to the module that says "use Lots::Of::Modules"
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
...
sub import {
my $caller = caller;
my $class = shift;
no strict;
*{ $caller. '::'. $_ } = \*{ $class. '::'. $_ }
for grep { !/(?:BEGIN|import)/ } keys %{ $class. '::' };
}
Затем используйте Lots:: Of:: Modules в другом месте;
use Lots::Of::Modules;
confess 'OH NOES';
Ответ 2
Да, это возможно, но нет, вы не должны этого делать.
Я просто потратил две недели, чтобы избавиться от модуля, который ничего не делал, кроме использования других модулей. Я предполагаю, что этот модуль стал простым и невинным. Но на протяжении многих лет он превращался в огромного зверя с множеством примеров использования, большинство из которых не были нужны ни для какого конкретного запуска нашего webapp. Наконец, потребовалось около 20 секунд, чтобы "использовать" этот модуль. И это поддерживало ленивое создание модулей копирования и вставки.
Так снова: вы можете сожалеть об этом шаге через пару месяцев или лет. И что вы получаете на стороне плюса? Вы сохранили набор двух строк в нескольких модулях. Большая сделка.
Ответ 3
Да.
В Foo/Corge.pm
use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;
1; # Be successful
Все, что осталось, - это получить каталог, содержащий подкаталог Foo
, добавленный в ваш путь к библиотеке (@INC
). В качестве альтернативы создайте Foo.pm
и используйте другие модули. Они будут находиться в подкаталоге Foo
рядом с Foo.pm
.
Если вы думаете об этом, все сложные модули Perl, которые используют другие модули, делают это все время. Они не обязательно находятся в одном пакете верхнего уровня (Foo
в этом примере), но они используются так же обязательно.
Пока вы можете использовать Carp, и Path:: Class, и признаться, и так далее (как предлагает jrockway), это кажется излишним, когда я сижу.
Ответ 4
[EDIT: мое раннее решение с участием use Lots::Of::Modules;
имело тонкую ошибку - см. нижнюю часть. Исправление делает вещи немного уродливыми, но все же работоспособными.]
[EDIT # 2: добавлен BEGIN { ... }
вокруг кода, чтобы гарантировать, что любые функции определены во время компиляции. Благодаря jrockway для указания этого.]
Следующий код будет делать именно то, что делает код jrockway, только проще и понятнее:
В лотах /Of/Modules.inc:
use Carp qw/confess cluck/;
use Path::Class qw/file dir/;
0; # Flag an error if called with "use" or "require" instead of "do"
Чтобы импортировать эти 4 функции:
BEGIN { defined( do 'Lots/Of/Modules.inc' ) or die; }
Поскольку у нас нет инструкции package Lots::Of::Modules;
в начале этого файла, операторы use
будут экспортироваться в пакет вызывающего абонента.
Мы должны использовать do
вместо use
или require
, так как последний будет загружать только один файл (вызывая отказ, если use Lots::Of::Modules;
вызывается более одного раза, например, в отдельных модулях use
d на основная программа). Более примитивный do
не генерирует исключение, если ему не удается найти файл, названный его аргументом в @INC
, следовательно, необходимость проверки результата с помощью defined
.
Ответ 5
Другим вариантом было бы для Foo:: Corge просто реэкспортировать любые интересующие предметы:
package Foo::Corge;
use base 'Exporter';
BEGIN {
our @EXPORT_OK = qw( bar baz qux quux );
use Foo::Bar qw( bar );
use Foo::Baz qw( baz );
use Foo::Qux qw( qux );
use Foo::Quux qw( quux );
}
1;
(Операторы использования могут, вероятно, выходить за пределы BEGIN
, но там, где они были в коде, который я проверил, чтобы убедиться, что это сработало так, как я думал. Это код на самом деле eval
the use
s, поэтому у него есть причина, чтобы они находились внутри BEGIN
, что, вероятно, не применимо в вашем случае.)
Ответ 6
используя @EXPORT вместо @EXPORT_OK, проще
Библиотека:
package mycommon;
use strict;
use warnings;
use base 'Exporter';
our @EXPORT = qw(test);
sub test {
print "this is a test";
}
1;
используйте его:
#!/usr/bin/perl
use strict;
use warnings;
use mycommon;
common::test()