Глава 12 Пакеты, библиотеки и модули

12.7. Ведение собственного каталога модулей

Проблема

Вы не хотите включать собственные модули в стандартную библиотеку расширений системного уровня.

Решение

Возможно несколько вариантов: воспользоваться параметром командной строки Perl -I; присвоить значение переменной окружения PERL5LIB; применить директиву use lib (возможно, в сочетании с модулем FindBin).

Комментарий

Массив @INC содержит список каталогов, которые просматриваются при каждс:" компиляции кода из другого файла, библиотеки или модуля командой do, require или use. Содержимое массива легко вывести из командной строки:
% perl -e 'for (@INC) { printf "%d %s\n", $i++, $_ }'
0 /usr/local/perl/lib/i686-linux/5.004
1 /usr/local/perl/lib
2 /usr/local/perl/lib/site_perl/i686-linux
3 /usr/local/perl/lib/site_perl
4 .

Первые два элемента (0 и 1) массива @INC содержат обычные платформенно-за-висимый и платформенно-независимый каталоги, с которыми работают все стандартные библиотеки, модули и директивы. Этих каталогов два, поскольку некоторые модули содержат данные и Следующая пара, элементы 2 и 3, по своим функциям аналогична элементам О и 1, но относится к конкретной системе. Допустим, у вас имеется модуль, который не поставлялся с Perl, - например, модуль, загруженный с CPAN или написанный вами. Когда вы (или, что Последний стандартный элемент, "." (текущий рабочий каталог), используется только в процессе разработки и тестирования программ. Если модули находятся в каталоге, куда вы перешли последней командой chdir, все хорошо. Если в любом другом месте - ничего не Иногда ни один из каталогов, указанных в @1МС, не подходит. Допустим, у вас имеются личные модули или ваша рабочая группа использует свой набор модулей, относящихся только к данному проекту. В этом случае необходимо дополнить поиск по стандартному содержи В первом варианте решения используется флаг командной строки -1список_ка-талогов. После флага указывается список из одного или нескольких каталогов, разделенных двоеточиями'. Список вставляется в начало массива @1МС. Этот вариант удобен для простых команд Подобную методику не следует использовать в строках #!. Во-первых, редактировать каждую программу в системе скучно. Во-вторых, в некоторых старых операционных системах имеются ошибки, связанные с ограничением длины этой строки (обычно 32 символа, включая #!). В этом случае очень длинный путь (например, й/opt/languages/Tree/extrabits/perl) приведет к появлению таинственной ошибки "Command not found" Нередко самое удачное решение заключается в использовании переменной окружения PERL5LIB, значение которой обычно задается в стартовом сценарии интерпретатора. Если системный администратор задаст переменную в стартовом файле системного уровня, результаты б
# Синтаксис для sh, bash, ksh и zsh $
export PERL5LIB=$HOME/perllib # Синтаксис для csh или tcsh
% setenv PERL5LIB '/perllib
Возможно, самое удобное решение с точки зрения пользователя - включение директивы use lib в начало сценария. При этом пользователям программы вообще не придется выполнять специальных действий для ее запуска. Допустим, у нас имеется гипотетический проект S
use lib "/projects/spectre/lib";

Что делать, если точный путь к библиотеке неизвестен? Ведь проект может устанавливаться в произвольный каталог. Конечно, можно написать детально проработанную процедуру установки с динамическим обновлением сценария, но даже в этом случае путь будет же
Модуль Find Bin легко решает эту проблему. Он пытается вычислить полный путь к каталогу выполняемого сценария и присваивает его важной пакетной переменной $Bin. Обычно он применяется для поиска модулей в одном каталоге с программой или в каталоге lib
Рассмотрим пример для первого случая. Допустим, у вас имеется программа wherever/spectre/my prog, которая ищет свои модули в каталоге /wherever/spectrem, однако вы не хотите жестко фиксировать этот путь:
use FindBin;
use lib $FindBin::Bin;

Второй случай - если ваша программа находится в каталоге /wherever/spectre/ bin/myprog, но ее модули должны находиться в каталоге /wherever/spectre/lib:
use FindBin qw($Bin);
use lib "$Bin/. . /lib" ;

[> Смотри также -------------------------------
Документация по стандартной директиве use lib и стандартному модулю FindBin. Переменная окружения PERL5LIB описана в perl(1). Переменные окружения рассматриваются в руководстве по синтаксису командного интерпретатора.

12.8. Подготовка модуля к распространению

Проблема

Вы хотите подготовить модуль в стандартном формате распространения, чтобы им можно было легко поделиться с другом. Или, что еще лучше, вы собираетесь загрузить модуль на CPAN и сделать его общедоступным.

Решение

Начните со стандартной утилиты Perl h2xs. Предположим, вы хотите создать модуль Planets или Astronomy::0rbits. Введите следующие команды:
% h2xs -ХА -n Planets % h2xs -ХА -n Astronomy::0rbits

Эти команды создают подкаталоги ./Planets/ и ./Astronomy/Orbits/ соответственно. В каталогах находятся все компоненты, необходимые для начала работы. Флаг -n задает имя создаваемого модуля, -X запрещает создание компонентов XS (внешних подпрограмм), а

Комментарий

Написать модуль несложно, если знать, как это делается. Написание "правильного" модуля похоже на заполнение юридического контракта - перед вами множество мест для инициалов, подписей и дат, и все нужно заполнить правильно. Если вы что-нибудь пропустите, к Название утилиты h2xs может сбить с толку, поскольку XS представляет собой интерфейс внешних подпрограмм Perl для компоновки с С или C++. Однако утилита h2xs также в высшей степени удобна для подготовки распространяемых модулей, даже если они и не использ Давайте рассмотрим один из модулей, созданных утилитой h2xs. Поскольку модуль будет называться Astronomy::0rbits, вместо команды use Orbits пользователь должен вводить use Astronomy: :0rbits. Следовательно, нам потребуется дополнительный подкаталог Astronomy, в котором будет размещаться ката..t л Orbits. Приведем первую и, вероятно, самую важную строку Orbits.pm: package Astronomy::0rbits; Команда определяет пакет (префикс по умолчанию) для всех глобальных \\h . тификаторов (переменных, функций, файловых манипуляторов и т. д.) дашк,1 файла. Следовательно, переменная @ISA в действительности является глобальи переменной ©Astronomy::0rbits::IS Как было сказано во введении, использовать команду package Orbits только потому, что она находится в файле Orbits.pm, будет ошибкой. Команда package модуле должна точно совпадать с формулировкой use или require; это означь присутствие префикса каталога, а
Если вы собираетесь использовать автоматическую загрузку (см. рецепт 12.10 уберите флаг -А из вызова h2xs. В результате будет создан фрагмент вида:
require Exporter;
require AutoLoader;
@ISA = qw(Exporter AutoLoader);

Если ваш модуль использует и Perl и С (см. рецепт 12.14), уберите флаг -X из вызова h2xs. Сгенерированный фрагмент выглядит так:
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
Далее перечисляются переменные модуля Exporter (см. рецепт 12.1). Если вы пишете объектно-ориентированный модуль (см. главу 13), вероятно, вам вообще не придется использовать Exporter. Подготовка завершена. Переходите к написанию кода своего модуля. Когда модуль будет готов к распространению, преобразуйте модуль в tar-архив для удобства распространения. Для этого используется команда make dist в командном интерпретаторе (имя программы m
%make dist

Команда создает файл с именем вида Astronomy-Orbits- 1.03-tar.Z. Чтобы зарегистрироваться в качестве разработчика CPAN, обратитесь по i,i',H су
htip://www.perl.com/CPAN/modules/04pause.html.

> Смотри также ------------------------------
h2xs(1) документация по стандартным модулям Exporter, AutoLoader, Auto-Split и ExtUtils::MakeMaker. По адресу http://www.perl.com/CPAN можно ' . : я ближайший зеркальный узел и рекомендации, касающиеся предостав-лсчия модулей.

12.9. Ускорение загрузки модуля с помощью SelfLoader

Проблема

Вам хочется быстро загрузить очень большой модуль.

Решение

Воспользуйтесь модулем SelfLoader:
require Exporter:
require SelfLoader;
@ISA = qw(Exporter SelfLoader); # # Прочие инициализации и объявления #
__DATA__
sub abc { .... }
sub def { .... }

Комментарий

При загрузке модуля командой require или use необходимо прочитать содержимое всего файла модуля и откомпилировать его (во внутренние деревья лексического анализа, не в байт-код или машинный код). Для очень больших модулей эта раздражающая задержка соверше Модуль SelfLoader решает эту проблему, откладывая компиляцию каждой подпрограммы до ее фактического вызова. Использовать SelfLoader несложно: достаточно расположить подпрограммы вашего модуля под маркером __ОАТА__, чтобы они были проигнорированы компилято
В модулях, использующих SelfLoader (или AutoLoader - см. рецепт 12.10), действует одно важное ограничение. Функции, загружаемые SelfLoader или AutoLoader, не имеют доступа к лексическим переменным файла, в чьем блоке __DATA__ они находятся, поскольку
Как скажется применение SelfLoader на быстродействии программы - положительно или отрицательно? Ответ на этот вопрос зависит от количества функ-ичй в модуле, от их размера и от того, вызываются ли они на протяжении всего жизненного цикла программы или Модуль SelfLoader не следует применять на стадии разработки и тестирова-,;|!ч модулей. Достаточно закомментировать строку __DATA__, и функции станут ггдны во время компиляции.

Смотри также -------------
Документация по стандартному модулю SelfLoader; рецепт 12.10.

12.10. Ускорение загрузки модуля с помощью Autoloader

Проблема

Вы хотите воспользоваться модулем AutoLoader.

Решение

Простейшее решение - воспользоваться утилитой h2xs для создания каталога и всех необходимых файлов. Предположим, у вас имеется каталог -/perllib, содержащий ваши личные библиотечные модули.
% h2xs -Xn Sample
% cd Sample
% perl Makefile.PL LIB=~/perllib
% (edit Sample.pm)
% make install

Комментарий

Модуль AutoLoader, как и SelfLoader, предназначен для ускорения работы программы. Он также генерирует функции-заглушки, которые заменяются настоящими функциями при первом вызове. Но вместо того чтобы искать все функции в одном файле под маркером __DATA__, Процесс подготовки выглядит сложно. Вероятно, сделать это вручную действительно непросто. К счастью, h2xs оказывает громадную помощь. Помимо создания каталога с шаблонами Sample.pm и других необходимых файлов, утилита также генерирует Make-файл, который и Как и в случае с SelfLoader, разработку и тестирование модуля лучше осуществлять без AutoLoader. Достаточно закомментировать строку __END__, пока МОДУЛ!) не придет к окончательному виду.
При работе с AutoLoader действуют те же ограничения видимости файловых лексических переменных, что и для SelfLoader, поэтому использование файловых лексических переменных для хранения закрытой информации состояния не подойдет. Если вопрос хранения состояния становится настолько важным и труднореализуемым, подумайте о том, чтобы написать объектный модуль вместо традиционного.

> Смотри также
Документация по стандартному модулю SelfLoader; h2xs(1); рецепт 12.9.

12.11. Переопределение встроенных функций

Проблема

Вы хотите заменить стандартную функцию собственной версией.

Решение

Импортируйте нужную функцию из другого модуля в свое пространство имен.

Комментарий

Многие (хотя и не все) встроенные функции Perl могут переопределяться. К этому шагу следует относиться серьезно, но в принципе это возможно. Например, необходимость в переопределении может возникнуть при работе на платформе, которая не поддерживает эмулир Не все зарезервированные слова одинаковы. Те, что возвращают отрицательное число в функции С keyword () файла token.c исходной поставки Perl, могут переопределяться. В версии 5.004 не допускалось переопределение следующих ключевых слов:chop,defined,delete Стандартный модуль Perl Cwd переопределяет функцию chdir. Также переопределение встречается во многих модулях с функциями, возвращающими списки: File::stat, Net::hostent, Net::netent, Net::protoent, Net::servent, Time::gmtime, Time::localtime, Time::tm, U
Переопределение осуществляется импортированием функции из другого пакета. Импортирование действует только в импортирующем пакете, а не во всех возможных пакетах. Простого переобъявления недостаточно, функцию необходимо импортировать. Это защищает от с
Предположим, вы решили заменить встроенную функцию time, которая возвращает целое количество секунд, другой, возвращающей вещественное число. Для этого можно создать модуль FineTime с необязательным экспортированием функции time: package FineTime;
use strict;
require Exporter;
use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(time);
sub time() {.....}

Затем пользователь, желающий использовать усовершенствованную версию time, пишет что-то вроде:
use FineTime qw(time);
$start = time();
1 while print time() - $start, "\n";

Предполагается, что в вашей системе есть функция, соответствующая приведенной выше спецификации. Некоторые решения, которые могут работать в вашей системе, рассматриваются в рецепте 12.14.
Переопределение методов и операторов рассматривается в главе 13.

> Смотри также -------------------------------
Раздел "Overriding Built-in Functions" perlsub(1)


© copyright 2000 Soft group
Используются технологии uCoz