Есть ли способ «использовать» один файл, который, в свою очередь, использует несколько других в Perl? - PullRequest
9 голосов
/ 13 января 2009

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

#!/usr/bin/perl

use Foo::Bar;
use Foo::Baz;
use Foo::Qux;
use Foo::Quux;

# Potentially many more.

Можно ли переместить все эти операторы в новый модуль Foo::Corge, и тогда в каждом из моих скриптов и модулей требуется только use Foo::Corge?

Ответы [ 6 ]

7 голосов
/ 13 января 2009

Да, это возможно, но нет, вы не должны этого делать.

Я потратил две недели, чтобы избавиться от модуля, который ничего не делал, кроме использования других модулей. Я предполагаю, что этот модуль изначально прост и невинен. Но за эти годы он превратился в огромного зверя с большим количеством заявлений о применении, большинство из которых не требовалось ни для какого запуска нашего веб-приложения. Наконец, потребовалось около 20 секунд, чтобы просто «использовать» этот модуль. И это поддержало ленивое создание модуля копирования и вставки.

Итак, еще раз: вы можете сожалеть об этом шаге через пару месяцев или лет. И что вы получаете на положительной стороне? Вы сохранили ввод нескольких строк в нескольких модулях. Большое дело.

7 голосов
/ 13 января 2009

Примерно так должно работать:

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';
3 голосов
/ 13 января 2009

Да.

In 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 и confess, и так далее (как предлагает jrockway), это похоже на излишество с того места, где я сижу.

0 голосов
/ 15 ноября 2013

с использованием @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()
0 голосов
/ 03 февраля 2009

Другим вариантом было бы для 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;

(операторы 'use', вероятно, могут выходить за пределы BEGIN, но именно там они и были в коде, который я проверил, чтобы убедиться, что это работает так, как я думал. Этот код на самом деле eval s use s, поэтому у них есть причина быть внутри BEGIN, что, скорее всего, не применимо в вашем случае.)

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

[РЕДАКТИРОВАТЬ: В моем предыдущем решении, включающем use Lots::Of::Modules;, была небольшая ошибка - см. Ниже. Исправление делает все немного уродливым, но все же работоспособным.]

[РЕДАКТИРОВАТЬ # 2: Добавлено BEGIN { ... } вокруг кода, чтобы гарантировать, что любые определенные функции доступны во время компиляции. Спасибо jrockway за указание на это.]

Следующий код будет делать то же, что и код jrockway, только проще и понятнее:

In Lots / 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...