2009-02-24 5 views
1

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

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

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

ответ

12

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

+0

@chaos Вот что я боялся: P Изначально я написал модуль А, как мне сказали, что это будет отдельный сценарий, затем он мутирует в стиле LAMP в веб-странице. благодаря – melaos

6

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

Теперь предположим, что у вас есть модуль под названием «Бар», который зависит от «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); 

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

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

2

Простой ответ заключается в том, чтобы не тестировать компилируемые модули с perl -c ... использовать perl -e'use Module ' или perl -e0 -MModule вместо этого. perl -c предназначен для выполнения тестовой компиляции скрипта, а не модуля. Когда вы запустите его на одном из ваших

При рекурсивном использовании модулей ключевым моментом является то, чтобы убедиться, что все внешние ссылки установлены раньше. Обычно это означает, что по крайней мере использование @ISA должно быть установлено во время построения компиляции (в BEGIN {} или через «использовать родительский» или устаревшую «базу использования»), а @EXPORT и друзей - в BEGIN {}.

Основная проблема заключается в том, что если модуль Foo использует модуль Bar (который использует Foo), компиляция Foo останавливается прямо в этой точке до тех пор, пока Bar не будет полностью скомпилирован и не будет выполнен основной код. Убедившись, что все части компиляции Foo Bar и код главной линии нужны, есть ответ.

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