Spec-Zone.ru › Perl 5.28

Exporter

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • СИНОПСИС
  • ОПИСАНИЕ
    • Как экспортировать
    • Выбор того, что экспортировать
    • Как импортировать
  • Дополнительные возможности
    • Специализированные списки импорта
    • Экспорт без использования метода импорта Exporter
    • Экспорт без наследования от Exporter
    • Проверка версии модуля
    • Управление неизвестными символами
    • Функции-утилиты для обработки тегов
    • Генерация объединённых тегов
    • Константы AUTOLOAD
  • Рекомендации по использованию
    • Объявление @EXPORT_OK и др.
    • Безопасность
    • Что не следует экспортировать
  • СМОТРИ ТАКЖЕ
  • ЛИЦЕНЗИЯ

НАЗВАНИЕ

Exporter - Реализует метод импорта по умолчанию для модулей

СИНОПСИС

В модуле YourModule.pm:

package YourModule;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(munge frobnicate);  # symbols to export on request

или

package YourModule;
use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(munge frobnicate);  # symbols to export on request

В других файлах, которые хотят использовать YourModule:

use YourModule qw(frobnicate);      # import listed symbols
frobnicate ($left, $right)          # calls YourModule::frobnicate

Обратитесь к "Рекомендациям по использованию" для вариантов, которые вам могут понравиться в современном Perl-коде.

ОПИСАНИЕ

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

Perl автоматически вызывает метод import при обработке оператора use для модуля. Модули и use документированы в perlfunc и perlmod. Понимание концепции модулей и того, как работает оператор use , важно для понимания Exporter.

Как экспортировать

Массивы @EXPORT и @EXPORT_OK в модуле содержат списки символов, которые будут экспортированы в пространство имён пользователя по умолчанию или по запросу соответственно. Символы могут представлять функции, скаляры, массивы, хэши или типы данных. Символы должны быть указаны полным именем, за исключением того, что амперсанд перед функцией является необязательным, например:

our @EXPORT    = qw(afunc $scalar @array);   # afunc is a function
our @EXPORT_OK = qw(&bfunc %hash *typeglob); # explicit prefix on &bfunc

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

Выбор того, что экспортировать

Не экспортируйте имена методов!

Не экспортируйте ничего по умолчанию без веской причины!

Экспорт загрязняет пространство имен пользователя модуля. Если вам необходимо экспортировать, старайтесь использовать @EXPORT_OK вместо @EXPORT и избегайте коротких или распространённых имён символов, чтобы уменьшить риск конфликтов имён.

Как правило, все, что не экспортируется, по-прежнему доступно извне модуля с использованием синтаксиса YourModule::item_name (или $blessed_ref->method). По соглашению, вы можете использовать ведущий символ подчёркивания для имён, чтобы указать, что они являются "внутренними" и не предназначены для общего использования.

(На самом деле, можно получить закрытые функции, указав:

my $subref = sub { ... };
$subref->(@args);            # Call it as a function
$obj->$subref(@args);        # Use it as a method

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

Как общее правило, если модуль пытается быть объектно-ориентированным, не экспортируйте ничего. Если это просто набор функций, то экспортируйте всё, но используйте @EXPORT с осторожностью. Для имён функций и методов используйте слова без префиксов в списках экспорта, предпочтительнее имён с префиксом амперсанда.

Другие рекомендации по проектированию модулей можно найти в perlmod.

Как импортировать

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

use YourModule;

Это импортирует все символы из @EXPORT YourModule в пространство имён оператора use .

use YourModule ();

Это вызывает загрузку вашего модуля, но не импортирует никакие символы.

use YourModule qw(...);

Это импортирует только перечисленные символы вызывающим в их пространство имён. Все перечисленные символы должны присутствовать в @EXPORT или @EXPORT_OK, в противном случае произойдёт ошибка. Дополнительные возможности экспорта Exporter используются таким же образом, но с элементами списка, которые синтаксически отличаются от имён символов.

Если вы не хотите использовать его дополнительные возможности, этого, вероятно, достаточно, чтобы использовать Exporter.

Дополнительные возможности

Специализированные списки импорта

Если любой из элементов списка импорта начинается с !, :, или /, то список обрабатывается как набор спецификаций, которые либо добавляют, либо удаляют из списка импортируемых имён. Они обрабатываются слева направо. Спецификации имеют вид:

[!]name         This name only
[!]:DEFAULT     All names in @EXPORT
[!]:tag         All names in $EXPORT_TAGS{tag} anonymous array
[!]/pattern/    All names in @EXPORT and @EXPORT_OK which match

Ведущая ! указывает, что соответствующие имена должны быть удалены из списка импортируемых имён. Если первая спецификация является удалением, она обрабатывается как если бы за ней следовал :DEFAULT. Если вы хотите просто импортировать дополнительные имена в дополнение к набору по умолчанию, вам всё равно необходимо явно указать :DEFAULT.

Например, Module.pm определяет:

our @EXPORT      = qw(A1 A2 A3 A4 A5);
our @EXPORT_OK   = qw(B1 B2 B3 B4 B5);
our %EXPORT_TAGS = (T1 => [qw(A1 A2 B1 B2)], T2 => [qw(A1 A2 B3 B4)]);

Обратите внимание, что вы не можете использовать теги в @EXPORT или @EXPORT_OK.

Имена в EXPORT_TAGS также должны присутствовать в @EXPORT или @EXPORT_OK.

Приложение, использующее Module, может сказать что-то вроде:

use Module qw(:DEFAULT :T2 !B3 A3);

Другие примеры включают:

use Socket qw(!/^[AP]F_/ !SOMAXCONN !SOL_SOCKET);
use POSIX  qw(:errno_h :termios_h !TCSADRAIN !/^EXIT/);

Помните, что большинство шаблонов (с использованием //) должны быть закреплены с ведущим ^, например, /^EXIT/ а не /EXIT/.

Вы можете сказать BEGIN { $Exporter::Verbose=1 } , чтобы увидеть, как обрабатываются спецификации и что фактически импортируется в модули.

Экспорт без использования метода импорта Exporter

Exporter имеет специальный метод 'export_to_level', который используется в ситуациях, когда вы не можете напрямую вызвать метод импорта Exporter. Метод export_to_level выглядит так:

MyPackage->export_to_level(
    $where_to_export, $package, @what_to_export
);

где $where_to_export — целое число, указывающее, насколько глубоко в стеке вызовов экспортировать символы, а @what_to_export — массив, указывающий, какие символы экспортировать (обычно это @_). Аргумент $package в настоящее время не используется.

Например, предположим, что у вас есть модуль A, у которого уже есть функция импорта:

package A;

our @ISA = qw(Exporter);
our @EXPORT_OK = qw($b);

sub import
{
    $A::b = 1;     # not a very useful import method
}

и вы хотите экспортировать символ $A::b обратно в модуль, который использовал пакет A. Поскольку Exporter полагается на метод импорта для работы через наследование, по умолчанию Exporter::import() никогда не будет вызван. Вместо этого сделайте следующее:

package A;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw($b);

sub import
{
    $A::b = 1;
    A->export_to_level(1, @_);
}

Это экспортирует символы на уровень «выше» текущего пакета — т. е. в программу или модуль, который использовал пакет A.

Примечание: Будьте внимательны, чтобы не изменять @_ до вызова export_to_level — в противном случае у пользователей вашего пакета могут возникнуть очень необъяснимые результаты!

Экспорт без наследования от Exporter

Включив Exporter в свой @ISA , вы наследуете метод импорта Exporter import(), но также наследуете несколько других вспомогательных методов, которых вам, вероятно, не нужно. Чтобы этого избежать, вы можете сделать следующее:

package YourModule;
use Exporter qw(import);

Это экспортирует собственный метод import() Exporter в YourModule. Всё будет работать как и раньше, но вам не нужно включать Exporter в @YourModule::ISA.

Примечание: Эта функция была добавлена в версии 5.57 Exporter, выпущенной с perl 5.8.3.

Проверка версии модуля

Модуль Exporter преобразует попытку импорта числа из модуля в вызов $module_name->VERSION($value). Это можно использовать для проверки того, что версия используемого модуля больше или равна требуемой версии.

По историческим причинам Exporter предоставляет метод require_version , который просто делегирует вызов VERSION. Первоначально, до существования UNIVERSAL::VERSION, Exporter вызывал require_version.

Поскольку метод UNIVERSAL::VERSION обрабатывает число $VERSION как простое числовое значение, он будет считать версию 1.10 как более низкую, чем 1.9. По этой причине настоятельно рекомендуется использовать числа с как минимум двумя десятичными знаками, например, 1.09.

Управление неизвестными символами

В некоторых ситуациях вам может потребоваться предотвратить экспорт определённых символов. Обычно это относится к расширениям, у которых есть функции или константы, которые могут отсутствовать на некоторых системах.

Имена любых символов, которые не могут быть экспортированы, должны быть перечислены в массиве @EXPORT_FAIL.

Если модуль пытается импортировать любой из этих символов, Exporter предоставляет модулю возможность обработать ситуацию до генерации ошибки. Exporter вызовет метод export_fail со списком не удавшихся символов:

@failed_symbols = $module_name->export_fail(@failed_symbols);

Если метод export_fail вернёт пустой список, то ошибка не регистрируется, и все запрошенные символы экспортируются. Если возвращённый список не пуст, то генерируется ошибка для каждого символа, и экспорт завершается неудачно. Exporter предоставляет метод export_fail по умолчанию, который просто возвращает список неизменным.

Возможности метода export_fail включают предоставление более информативных сообщений об ошибках для некоторых символов и выполнение ленивых архитектурных проверок (включите больше символов в @EXPORT_FAIL по умолчанию, а затем удалите их, если кто-то действительно пытается их использовать, и дорогостоящая проверка показывает, что они применимы на этой платформе).

Функции-утилиты для обработки тегов

Поскольку символы, перечисленные в %EXPORT_TAGS, также должны присутствовать в @EXPORT или @EXPORT_OK, предоставляются две вспомогательные функции, которые позволяют легко добавлять помеченные наборы символов в @EXPORT или @EXPORT_OK:

our %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);

Exporter::export_tags('foo');     # add aa, bb and cc to @EXPORT
Exporter::export_ok_tags('bar');  # add aa, cc and dd to @EXPORT_OK

Любые имена, которые не являются тегами, добавляются в @EXPORT или @EXPORT_OK без изменений, но будут вызывать предупреждение (с -w) для предотвращения неявного добавления неправильно написанных имён тегов в @EXPORT или @EXPORT_OK. В будущих версиях это может стать фатальной ошибкой.

Создание комбинированных тегов

Если в %EXPORT_TAGS существуют несколько категорий символов, обычно полезно создать вспомогательный тег ":all" для упрощения операторов "использовать".

Самый простой способ сделать это:

our  %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);

 # add all the other ":class" tags to the ":all" class,
 # deleting duplicates
 {
   my %seen;

   push @{$EXPORT_TAGS{all}},
     grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}} foreach keys %EXPORT_TAGS;
 }

CGI.pm создаёт тег ":all", который содержит некоторые (но не все) из его категорий. Это можно сделать с одной небольшой правкой:

# add some of the other ":class" tags to the ":all" class,
# deleting duplicates
{
  my %seen;

  push @{$EXPORT_TAGS{all}},
    grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}}
      foreach qw/html2 html3 netscape form cgi internal/;
}

Обратите внимание, что имена тегов в %EXPORT_TAGS не имеют ведущего ':'.

AUTOLOAD константы

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

Даже если прототип доступен во время компиляции, тело подпрограммы нет (ещё не AUTOLOAD). perl нужно изучить как прототип (), так и тело подпрограммы во время компиляции, чтобы определить, может ли он безопасно заменить вызовы этой подпрограммы константным значением.

Обходным путём является вызов констант в блоке BEGIN:

package My ;

use Socket ;

foo( SO_LINGER );  ## SO_LINGER NOT optimized away; called at runtime
BEGIN { SO_LINGER }
foo( SO_LINGER );  ## SO_LINGER optimized away at compile time.

Это заставляет AUTOLOAD для SO_LINGER произойти до того, как встретится SO_LINGER в My пакете позже.

Если вы пишете пакет, AUTOLOAD , рассмотрите возможность принудительного выполнения AUTOLOAD для любых констант, явно импортированных другими пакетами или обычно используемых, когда ваш пакет use.

Рекомендации по стилю

Объявление @EXPORT_OK и Другие

При использовании Exporter со стандартными strict и warnings пragmaми, необходимо использовать ключевое слово our для объявления переменных пакета @EXPORT_OK, @EXPORT, @ISA и т. д.

our @ISA = qw(Exporter);
our @EXPORT_OK = qw(munge frobnicate);

Если обратная совместимость для Perls ниже 5.6 важна, необходимо написать вместо этого оператор use vars.

use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(munge frobnicate);

Безопасность

Существуют некоторые моменты, связанные с использованием операторов времени выполнения, таких как require Exporter и присвоение переменных пакетам, которые могут быть очень тонкими для неопытного программиста. Это может произойти, например, с взаимно рекурсивными модулями, которые зависят от времени выполнения соответствующих конструкций.

Идеальный (но немного некрасивый) способ избежать необходимости думать об этом — использовать блоки BEGIN . Таким образом, первая часть кода в "ПРИМЕРЫ" можно переписать как:

package YourModule;

use strict;
use warnings;

our (@ISA, @EXPORT_OK);
BEGIN {
   require Exporter;
   @ISA = qw(Exporter);
   @EXPORT_OK = qw(munge frobnicate);  # symbols to export on request
}

BEGIN гарантирует, что загрузка Exporter.pm и присвоения @ISA и @EXPORT_OK произойдут немедленно, не оставляя места для сбоев или ошибок.

Что касается загрузки Exporter и наследования, существуют альтернативы с использованием модулей, таких как base и parent.

use base qw(Exporter);
# or
use parent qw(Exporter);

Любой из этих операторов является хорошей заменой для BEGIN { require Exporter; @ISA = qw(Exporter); } с тем же эффектом на этапе компиляции. Основное различие заключается в том, что код base взаимодействует с объявленными fields, в то время как parent — это усовершенствованная версия старого кода base для простого установления отношения IS-A.

Дополнительные сведения см. в документации и коде base и parent.

Ещё одним эффективным способом решения проблемы с временными рамками выполнения и компиляции является использование Exporter::Easy, который является оболочкой Exporter, позволяющей выполнить весь вспомогательный код в одном операторе use.

use Exporter::Easy (
    OK => [ qw(munge frobnicate) ],
);
# @ISA setup is automatic
# all assignments happen at compile time

Что не следует экспортировать

В разделе "Выбор того, что экспортировать" вас уже предупредили о том, чтобы не экспортировать:

  • имена методов (потому что вам они не нужны, и это, вероятно, не то, чего вы хотите),

  • ничего по умолчанию (потому что вы не хотите удивлять своих пользователей... сильно),

  • ничего, что вам не нужно (потому что меньше — это больше).

Ещё один пункт в этот список. Не экспортируйте имена переменных. Просто потому, что Exporter позволяет это сделать, не значит, что вы должны.

@EXPORT_OK = qw($svar @avar %hvar); # DON'T!

Экспорт переменных — плохая идея. Они могут измениться внутри, вызывая ужасные побочные эффекты, которые слишком трудно отслеживать и исправлять. Поверьте мне: они того не стоят.

Чтобы предоставить возможность устанавливать/получать параметры класса, лучше вместо этого предоставить методы доступа в виде подпрограмм или методов класса.

См. также

Exporter определённо не единственный модуль с возможностями экспорта символов. В CPAN можно найти множество таких модулей. Некоторые из них более лёгкие. Некоторые предлагают улучшенные API и функции. Выберите тот, который соответствует вашим потребностям. Ниже приведён примерный список таких модулей.

Exporter::Easy
Exporter::Lite
Exporter::Renaming
Exporter::Tidy
Sub::Exporter / Sub::Installer
Perl6::Export / Perl6::Export::Attrs

ЛИЦЕНЗИЯ

Эта библиотека — свободное программное обеспечение. Вы можете перераспределять и/или изменять её в соответствии с теми же условиями, что и Perl.

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.28.3/Exporter

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API