Как лучше всего иметь два модуля, которые используют функции друг от друга в Perl?
К сожалению, я совершенно нуб, когда дело доходит до создания пакетов, экспорта и т. Д. В Perl. Я пытался прочитать некоторые из модулей и часто обнаруживал, что задремал из длинных глав. Было бы полезно, если бы я мог найти то, что мне нужно понять, на одной простой веб-странице без необходимости прокрутки вниз.:П
В основном у меня есть два модуля, A и B, и A будет использовать некоторые функции из B, а B будет использовать некоторые функции из A. Я получаю массу предупреждений о функции, переопределенной, когда я пытаюсь скомпилировать через perl -c
,
Есть ли способ сделать это правильно? Или мой дизайн отсталый? Если так, что было бы лучше? По этой причине я стараюсь не копировать и не вставлять другие функции модуля в этот модуль и не переименовывать их.
3 ответа
Не очень хорошая практика иметь круговые зависимости. Я бы посоветовал перевести что-то в третий модуль, чтобы вы могли получить A, зависящее от B, A - от C, B - от C.
Итак... предложение вынести общий код в другой модуль - это хорошо. Но вы не должны называть модули *.pl, и вы не должны загружать их require
-на определенном пути (как в require
"../lib/foo.pl";
). (С одной стороны, если сказать "..", ваш скрипт будет зависеть от того, выполняется ли он каждый раз из одного и того же рабочего каталога. Поэтому ваш скрипт может работать, когда вы запускаете его как perl foo.pl
, но это не сработает, когда вы запустите perl YourApp/foo.pl
, Это вообще не хорошо.)
Допустим, ваше приложение называется YourApp. Вы должны построить свое приложение как набор модулей, которые живут в lib/
каталог. Например, вот модуль "Foo"; его имя файла lib/YourApp/Foo.pm
,
package YourApp::Foo;
use strict;
sub do_something {
# code goes here
}
Теперь предположим, что у вас есть модуль под названием "Bar", который зависит от "Foo". Вы просто делаете lib/YourApp/Bar.pm
и скажи:
package YourApp::Bar;
use strict;
use YourApp::Foo;
sub do_something_else {
return YourApp::Foo::do_something() + 1;
}
(В качестве расширенного упражнения вы можете использовать Sub::Exporter
или же Exporter
делать use YourApp::Foo
установите подпрограммы в пространство имен потребляющего пакета, чтобы вам не приходилось писать YourApp::Foo::
до всего.)
Во всяком случае, вы создаете все свое приложение, как это. Логические части функционально должны быть сгруппированы в модули (или, что еще лучше, в классы).
Чтобы все это запустить, вы пишете небольшой скрипт, который выглядит следующим образом (я положил их в bin/
так давайте назовем это bin/yourapp.pl
):
#!/usr/bin/env perl
use strict;
use warnings;
use feature ':5.10';
use FindBin qw($Bin);
use lib "$Bin/../lib";
use YourApp;
YourApp::run(@ARGV);
Ключевым моментом здесь является то, что ни один из вашего кода не находится за пределами модулей, за исключением крошечного шаблона для запуска вашего приложения. Это легко поддерживать и, что более важно, облегчает написание автоматических тестов. Вместо запуска чего-либо из командной строки, вы можете просто вызвать функцию с некоторыми значениями.
Во всяком случае, это, вероятно, не по теме сейчас. Но я думаю, что это важно знать.
Простой ответ - не тестировать модули компиляции с помощью perl -c... вместо этого используйте perl -e'use Module'или perl -e0 -MModule. Perl -c предназначен для тестовой компиляции скрипта, а не модуля. Когда вы запускаете его на одном из ваших
При рекурсивном использовании модулей ключевым моментом является обеспечение того, чтобы что-либо внешне ссылающееся было установлено на ранней стадии. Обычно это означает, что по крайней мере использование @ISA должно быть установлено в конструкции времени компиляции (в BEGIN{} или через "use parent" или устаревшую "use base"), а @EXPORT и friends должны быть установлены в BEGIN{}.
Основная проблема заключается в том, что если модуль Foo использует модуль Bar (который использует Foo), компиляция Foo останавливается прямо в этой точке, пока Bar не будет полностью скомпилирован и его основной код не будет выполнен. Чтобы убедиться в том, что какие-то части кода Foo Bar, необходимые для компиляции и запуска основного кода, есть ответ.
(Во многих случаях вы можете разумно разделить функциональность на несколько модулей и разбить рекурсию. Это лучше всего.)