Створення пакетів і модулів в Perl
У цій статті ми розглянемо процес створення пакетів і модулів і як приклад створимо один простий модуль і пакет.
Intro
Захищеність і модульність - два великі принципи програмування. Perl забезпечує їх виконання, надаючи можливість розбивати програму на напівавтономні фрагменти так, що програмістові не треба турбуватися про конфлікти між ними і рештою частини програми. Для ділення програми на незалежні фрагменти використовуються пакети Perl, які створюють непересічні області імен (namespaces). Що таке область імен? Це частина програми зі власне своєю областю видимості глобальних ідентифікаторів - іншими словами, вона функціонує як приватна територія програміста.
Насправді в Perl немає такої речі, як “область видимості глобальних ідентифікаторів”, - будь-яка така область обмежується якимось пакетом. Створюючи пакет, ви отримуєте якусь гарантію того, що ваш код не змішається із змінними і підпрограмами іншого фрагмента. Це дозволяє організовувати код, призначений для багатократного використання, у вигляді пакетів.
Окрім пакетів існують також модулі Perl. Моудлі - це пакети, організовані спеціальним чином. Їх можна завантажувати і інтегрувати з конкретною програмою. У цій статті піде мова про створення модулів і пакетів.
Пакети
Пакет можна представити у вигляді юніта Delphi. Код, що поміщається в пакет, може розміщуватися в зовнішньому файлі, в декількох файлах, хоча декілька пакетів можуть розміщуватися в одному файлі (що неможливо зробити в делфійскому юніті). Перемикатися між різними пакетами усередині файлу потрібно за допомогою команди package. Давайте створимо простій пакет і збережемо його як package1.pl:
package package1;
BEGIN { }
sub subroutine1 {print “Hello!\n”;}
return 1;
END { }
Команда package починає новий пакет package1. Зверніть увагу на підпрограми BEGIN і END. Перша підпрограма виконується відразу ж після завантаження пакету. Тому в неї зазвичай поміщають код, що ініціалізувався. Хоча вірніше було б стверджувати, що підпрограма BEGIN виконується як тільки інтерпретатор доходить до неї, тобто до закінчення завантаження пакету. А підпрограма END виконується при завершенні роботи інтерпретатора і може містити код, що виконує завершальні оперпации (наприклад закриття відкритих файлів. Підпрограми BEGIN і END викликаються неявним чином (більш того, вам ніколи не вдасться явно викликати BEGIN: інтерпретатор знищує її відразу ж після використання). Саме тому ці підпрограми складаються із заголовних букв, і ключове слово sub для них можна не вказувати.
Зверніть увагу на підпрограму subroutine1. Її можна викликати в межах коду, що використовує пакет. Крім того, варто звернути увагу на команду return, розташовану поза якими-небудь підпрограмами, - вона повертає значення “істина” після завантаження пакету, показуючи таким чином, що пакет готовий до роботи (насправді повертається останнє значення, обчислене в тілі пакету, тому часто замість рядка return 1 ставиться просто одиниця).
Що б використовувати в програмі код пакету, необхідно помістити в сценарій команду require:
require “package1.pl”;
Тепер можна посилатися на ідентифікатори пакету package1, відокремивши його ім’я від ідентифікатора двома двокрапками “::”. Раніше в ролі роздільника був апостроф (будьте уважні, тому що цей роздільник використовується і зараз). Але тепер Perl слідує стилю C++ і використовує “::”. Ось приклад виклику підпрограми subroutine1 з пакету package1:
require “package1.pl”;
package1::subroutine1();
Як результат роботи цієї програми буде виведений напис “Hello!”. Можна також в пакети поміщати інші ідентифікатори, наприклад змінні:
package package1;
BEGIN { }
$var1=1;
sub subroutine1 {print “Hello!\n”;}
return 1;
END { }
Використовувати цю змінну легко. Досить підставити символ “$” перед конструкцією виклику. Приклад:
require “package1.pl”;
$package1::var1;
Звернете увагу, що символ “$” ставиться перед ім’ям пакету, але НЕ ставиться після :: перед var1. Проте у такий спосіб неможливо дістатися до змінних, описаних з ключовим словом my: вони володіють лексичною областю видимості і доступні тільки усередині модуля.
При зверненні до ідентифікаторів можна опускати ім’я пакету, і тоді буде використаний пакет main (рядок $::var1 еквівалентна $main:var1).
Якщо в програмі потрібно досить часто звертатися до ідентифікаторів з пакетів, то код стає великим і малозрозумілим. Що б вирішити цю проблему потрібно використовувати модулі. При використанні модулів можна експортувати імена, вказані в модулі в текущу область імен.
Модулі
Модулі - це пакети, оформлені в окремих файлах, у яких імена останніх співпадають з іменами модулів і мають розширення pm. За угодою Perl визначає, що ім’я модуля починається із заголовної букви. Код, що міститься в модулі, на відміну від “пакетного” коду, може експортувати глобальні імена в текущу область глобальних імен. Це означає, що при зверненні до ідентифікатора не потрібно вказувати ім’я пакету.
Розглянемо приклад. Створіть модуль з ім’ям Module1 і збережіть його у файлі Module1.pm. У коді підпрограми BEGIN, що виконується при завантаженні модуля, використовуватимемо стандартний модуль Exporter, що б експортувати ім’я підпрограми subroutine1:
package Module1;
BEGIN {
use Exporter ();
@ISA = “Exporter”;
@EXPORT = “&subroutine1″;
}
sub subroutine1 {print “Hello!\n”;}
return1;
END { }
Для використання модуля в програмі потрібно підключити його за допомогою команди “use” (він буде включений у момент компіляції). Якщо ж підключити модуль командою require то модуль підключиться у момент виконання сценарію. Приклад:
use Module1;
subroutine1();
В результаті виконання цього коду буде виведений рядок “Hello!”.
Outro
Ця стаття не пертендує на повноту опису модулів і пакетів. Існує ще багато, чого ви не дізналися з цієї статті: пакети можна вкладати один в одного, дозволяти експортувати певні імена і не експортувати їх за замовчуванням і навіть викликати неіснуючі підпрограми. Але це тема величезного розділу книги, якщо не всієї книги.
При підготовці статті були використані матеріали з книги “Perl. Спеціальний довідник” (автор Стівен Холзнер, видавництво “Пітер”, 2001 р.)
Brutus aka Осипов Олексій