Как лучше всего иметь два модуля, которые используют функции друг от друга в Perl? - PullRequest
1 голос
/ 24 февраля 2009

К сожалению, я совершенно нуб, когда дело доходит до создания пакетов, экспорта и т. Д. В Perl. Я пытался прочитать некоторые из модулей и часто обнаруживал, что задремал из длинных глав. Было бы полезно, если бы я мог найти то, что мне нужно понять, на одной простой веб-странице без необходимости прокрутки вниз. : P

В основном у меня есть два модуля, A & B и A, которые будут использовать некоторые функции из B, а B будут использовать некоторые функции из A. Я получаю массу предупреждений о переопределении функций, когда пытаюсь скомпилировать с помощью perl -c .

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

Ответы [ 3 ]

12 голосов
/ 24 февраля 2009

Не очень хорошая практика иметь круговые зависимости. Я бы посоветовал перевести что-то в третий модуль, чтобы у вас было A зависит от B, A зависит от C, B зависит от C.

6 голосов
/ 24 февраля 2009

Итак ... предложение вынести общий код в другой модуль хороший. Но вы не должны называть модули * .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 для make 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);

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

Во всяком случае, сейчас это, вероятно, не по теме. Но я думаю, что это важно знать.

2 голосов
/ 24 февраля 2009

Простой ответ - не тестировать модули компиляции с помощью 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 компилируются и запускаются из mainline-кода нужен ответ.

(Во многих случаях вы можете разумно разделить функциональность на несколько модулей и разбить рекурсию. Это лучше всего.)

...