Как я могу экспортировать все сабвуферы в пакете Perl? - PullRequest
18 голосов
/ 09 апреля 2009

Я хотел бы выставить все сабвуферы в свое пространство имен без необходимости перечислять их по одному:

@EXPORT = qw( firstsub secondsub third sub etc );

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

Есть ли @EXPORT_ALL?

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

Чтобы ответить на вопрос Джона: сейчас, для быстрого рефакторинга, я хочу переместить группу подпрограмм в их собственный пакет с наименьшими трудностями и изменениями кода в существующих сценариях (где эти подпрограммы используются и часто повторяются).

Кроме того, в основном мне было просто любопытно. (поскольку казалось, что Exporter может иметь такую ​​же стандартную функцию, но, на удивление, основывается на ответах, которых пока нет)

Ответы [ 9 ]

23 голосов
/ 09 апреля 2009

Не делайте никакого экспорта и не объявляйте имя пакета в вашей библиотеке. Просто загрузите файл с require, и все будет в текущем пакете. Легкий горох.

10 голосов
/ 09 апреля 2009

Не. Но если вы действительно хотите ... написать пользовательский import, который обходит таблицу символов и экспортирует все названные подпрограммы.

# Export all subs in package. Not for use in production code!
sub import {
    no strict 'refs';

    my $caller = caller;

    while (my ($name, $symbol) = each %{__PACKAGE__ . '::'}) {
        next if      $name eq 'BEGIN';   # don't export BEGIN blocks
        next if      $name eq 'import';  # don't export this sub
        next unless *{$symbol}{CODE};    # export subs only

        my $imported = $caller . '::' . $name;
        *{ $imported } = \*{ $symbol };
    }
}
3 голосов
/ 09 апреля 2009

Внимание, следующий код является такой же плохой идеей, как экспорт всего:

package Expo;

use base "Exporter";

seek DATA, 0, 0; #move DATA back to package

#read this file looking for sub names
our @EXPORT = map { /^sub\s+([^({\s]+)/ ? $1 : () } <DATA>;

my $sub = sub {}; #make sure anon funcs aren't grabbed

sub foo($) {
    print shift, "\n";
}

sub bar ($) {
    print shift, "\n";
}

sub baz{
    print shift,"\n";
}

sub quux {
    print shift,"\n";
}

1;

__DATA__

Вот код, который использует модуль:

#!/usr/bin/perl

use strict;
use warnings;

use Expo;

print map { "[$_]\n" } @Expo::EXPORT;

foo("foo");
bar("bar");
baz("baz");
quux("quux");

И вот его вывод:

[foo]
[bar]
[baz]
[quux]
foo
bar
baz
quux
2 голосов
/ 11 октября 2014

https://metacpan.org/pod/Exporter::Auto

экспортёр :: Авто. это все, что вам нужно.

2 голосов
/ 09 апреля 2009

Возможно, вас заинтересует один из модулей экспорта * в CPAN, который позволяет пометить подпрограммы как экспортируемые, просто добавив атрибут в определение? (Хотя не помню, какой именно.)

2 голосов
/ 09 апреля 2009

Вы всегда можете вызвать подпрограммы в там полностью указанной форме:

MyModule::firstsub();

Для модулей, которые я пишу внутри, я считаю, что это соглашение работает довольно хорошо. Это немного больше печатает, но лучше документация.

Посмотрите на perldoc perlmod для получения дополнительной информации о том, чего вы пытаетесь достичь.

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

 package main;
 sub firstsub() { ... }

(Не думаю, что это хорошая идея, но вы знаете лучше, чем я, что вы пытаетесь достичь.)

В этом нет ничего плохого при условии вы знаете, что делаете, и не просто пытаетесь не думать о вашем интерфейсе с внешним миром.

1 голос
/ 15 ноября 2013

корпус 1

Библиотека:

package mycommon;

use strict;
use warnings;

sub onefunctionthatyoumadeonlibary() {
}
1;

Вы можете использовать его, вызывая общий :::

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

common::onefunctionthatyoumadeonlibary()

кейс 2

Библиотека есть, вы можете просто экспортировать их:

package mycommon;

use strict;
use warnings;

use base 'Exporter';

our @EXPORT = qw(onefunctionthatyoumadeonlibary);
sub onefunctionthatyoumadeonlibary() {
}
1;

используйте его в том же «пространстве имен»:

#!/usr/bin/perl
use strict;
use warnings;
use mycommon qw(onefunctionthatyoumadeonlibary);

onefunctionthatyoumadeonlibary()

Также мы можем сделать смесь этих двух случаев, мы можем экспортировать более общие функции, чтобы использовать их без вызова имени пакета и других функций, которые мы вызываем только с именем пакета, и которые не нужно экспортировать.

1 голос
/ 02 апреля 2013

Хотя обычно нецелесообразно выгружать все sub s из модуля в пространство имен вызывающего, иногда полезно (и более DRY!) Автоматически генерировать @EXPORT_OK и %EXPORT_TAGS переменные.

Самый простой способ - расширить экспортер. Простой пример примерно такой:

package Exporter::AutoOkay;
#
#   Automatically add all subroutines from caller package into the
#   @EXPORT_OK array. In the package use like Exporter, f.ex.:
#
#       use parent 'Exporter::AutoOkay';
#
use warnings;
use strict;
no strict 'refs';

require Exporter;

sub import {
    my $package = $_[0].'::';

    # Get the list of exportable items
    my @export_ok = (@{$package.'EXPORT_OK'});

    # Automatically add all subroutines from package into the list
    foreach (keys %{$package}) {
        next unless defined &{$package.$_};
        push @export_ok, $_;
    }

    # Set variable ready for Exporter
    @{$package.'EXPORT_OK'} = @export_ok;

    # Let Exporter do the rest
    goto &Exporter::import;
}

1;

Обратите внимание на использование goto, которое удаляет нас из стека вызывающих.

Более полный пример можно найти здесь: http://pastebin.com/Z1QWzcpZ Он автоматически генерирует группы тегов из префиксов подпрограмм.

0 голосов
/ 09 апреля 2009

Тебе нужно будет немного поковыряться. Я описываю что-то подобное здесь:

Есть ли способ "использовать" один файл, который в свою очередь использует несколько других в Perl?

Процедура импорта там должна делать именно то, что вы хотите - только не импортируйте символы в ваше собственное пространство имен.

...