Как использовать сабу из Perl скрипта

Задача. Есть скрипт на языке программирования Perl. В нем определена какая-то функция (саба). Нужно заиспользовать эту функцию в другом скрипте.

Вот пример. Есть скрипт script.pl в котором определена саба header. В эту сабу передаешь строку, и она возвращает эту строку в виде markdown заголовка. В этом скрипте эта саба используется для того чтобы вывести на экран два заголовка:

▶ Run
#!/usr/bin/perl

use feature qw(say);

sub header {
    my ($string) = @_;

    return '## ' . uc($string);
}

say header('one');
say header('two');

Запускаем perl script.pl и видим на экране:

## ONE
## TWO

Задача — создать еще один скрипт other.pl который тоже будет использовать эту сабу.

Решение — copy-paste

Самое простое (но плохое) решение — это просто скопировать код сабы в другой скрипт. При таком решении получается вот такой other.pl:

#!/usr/bin/perl

use feature qw(say);

sub header {
    my ($string) = @_;

    return '## ' . uc($string);
}

say header('three');

Теперь можно запустить этот скрипт perl other.pl и увидеть на экране текст ## THREE.

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

Решение — вынести сабу в отдельный модуль

Наиболее правильное решение, — это вынести сабу в отдельный модуль. Для этого создаем файл lib/Utils.pm:

package Utils;

use strict;
use warnings;

use Exporter;

our @ISA = qw(Exporter);
our @EXPORT_OK = qw(
    header
);
our @EXPORT = @EXPORT_OK;

sub header {
    my ($string) = @_;

    return '## ' . uc($string);
}

1;
  • package Utils; - объявили что это "библиотека" Utils
  • use strict; и use warnings; — включаем режим чтобы Perl был более требователен к хорошему коду
  • 5 строки про EXPORT говорят о том что при подключении этой "библиотеки" нужно чтобы функция header была доступна
  • перенесли сюда функцию
  • 1; — package всегда должен заканчиваться истиной

После этого описание функции нужно из скрипта script.pl убрать, но добавить подключение библиотеки:

#!/usr/bin/perl

use feature qw(say);

use Utils;

say header('one');
say header('two');

После этого можно запустить этот же скрипт с помощью команды perl -Ilib/ script.pl. В ключ командной строки -I передаем значение lib/ — папка в которой Perl будет искать библиотеки. Результат работы этого скрипта точно такой же как и раньше.

И теперь совершенно тривиально заиспользовать эту же сабу в другом скрипте. Пишем скрипт other.pl, который практически такой же как script.pl:

#!/usr/bin/perl

use feature qw(say);

use Utils;

say header('three');

Запускаем этот скрипт perl -Ilib/ other.pl и видим на экране ## THREE.

Решение — подключить код скрипта в скрипт

Существует еще одно решение как можно использовать сабу определенную в скрипте script.pl заиспользовать в скрипте other.pl. Для этого пишем такой текст в файл other.pl:

#!/usr/bin/perl

use feature qw(say);

require './script.pl';

say header('three');

Запускаем скрипт perl other.pl (файл other.pl должен быть в той же папке что и скрипт script.pl). Результат:

## ONE
## TWO
## THREE

Т.е. получилось что при выполнении скрипта other.pl сначала был выполнен весь код, который был в script.pl (строки ## ONE и ## TWO), а только потом выполнен код из скрипта other.pl (строка ## THREE).

Для того чтобы при запуске скрипта other.pl не выполнялась часть script.pl нам нужно немного изменить script.pl. Нужно завернуть весь код в теле скрипта под условие и вписать в конец скрипта единицу как истинное значение:

#!/usr/bin/perl

use feature qw(say);

sub header {
    my ($string) = @_;

    return '## ' . uc($string);
}

if ( not caller() ) {
    say header('one');
    say header('two');
}

1;

Теперь если мы запустим perl script.pl, то получим точно такой же вывод как и раньше, а если запустим perl other.pl, то в выводе будет только нужный нам текст ## THREE.

Ключевое слово caller возвращает разные значение в зависимости от того как был запущен скрипт. Эту фичу мы используем здесь для того чтобы разделить запуск скрипта напрямую от подключения скрипта с использованием require.

Другие статьи

Комментарии