*** Ниже приведена справочная информация, чтобы помочь объяснить, что я пробовал до сих пор Если вы предпочитаете сначала прочитать основной вопрос, перейдите к нижней части. ***
Начиная с
Мой Baz
модуль вызывает ряд других модулей, все похожие, каждый из которых находится на один уровень ниже в пространстве имен. Интересующие нас здесь составляют роль Thing
. В дополнение к отдельным операторам require
в списке констант ALL_THINGS
перечислены соответствующие модули Thing
для последующего использования. Мой оригинальный код выглядит так:
package Foo::Bar::Baz;
use constant ALL_THINGS => qw{ Foo::Bar::Baz::ThingA Foo::Bar::Baz::ThingB ... };
require Foo::Bar::Baz::ThingA;
require Foo::Bar::Baz::ThingB;
[...]
Устранение избыточности
Как я уже говорил, модулей Thing
довольно много, и я все еще добавляю больше. Каждый раз, когда я создаю новый класс Thing
, я должен добавить новый оператор require
, а также добавить тот же идентичный текст в список ALL_THINGS
. Чтобы избежать этого дублирования, я хотел заменить отдельные строки require
циклом, повторяющимся по ALL_THINGS
. Я добавил это, которое прекрасно работает само по себе:
foreach my $module (ALL_THINGS) {
eval "require $module";
}
Однако, похоже, это решение не совсем подходит для моих следующих изменений.
Улучшение читаемости
Полное имя модуля для каждого Thing
длинное и громоздкое. Я хотел бы присвоить псевдониму имя пакета, чтобы его было легче набирать / читать. Я посмотрел на Package::Alias
, но, похоже, их будет use
, которых я бы хотел избежать, если это возможно. Лучшее решение, к которому я пришел, это шаблон, предложенный в этом вопросе :
BEGIN { *Things:: = *Foo::Bar::Baz:: ; }
Это также работает, в том смысле, что позволяет мне использовать Thing::ThingA->classMethod
. Однако неудивительно, что он не работает в вышеуказанном цикле require
, так как require Thing::ThingA
ищет @INC
для Thing/ThingA.pm
, а не Foo/Bar/Baz/ThingA.pm
.
Главный вопрос: собрать их вместе
Я хотел бы сократить длинные имена пакетов (например, Foo::Bar::Baz::ThingA
) в моем списке ALL_THINGS
до Things::ThingA
, но все же иметь возможность использовать этот же список для построения моих операторов require
в цикле ,
- Есть ли другой способ использовать псевдоним
Foo::Bar::Baz::
как Things::
, чтобы я мог require Things::ThingA
?
- Или, если я правильно делаю часть псевдонима, есть ли способ разыменовать
Things::ThingA
на Foo::Bar::Baz::ThingA
в (или раньше?) В eval, чтобы require
нашел правильный пакет?
- Существует ли какой-либо другой общепринятый метод связывания пакетов на разных уровнях одного и того же пространства имен, чтобы устранить необходимость во всем этом?
Бонусные вопросы (связанные с eval "require $x"
):
- В perldoc для константы говорится, что списки констант на самом деле не только для чтения. Создает ли это проблему безопасности при использовании
eval
?
- Если это так, есть ли более безопасный способ сделать это без необходимости загружать дополнительные модули?
- Будучи несколько новичком в Perl, есть ли еще какие-то тонкие различия, которые я мог бы пропустить между этим подходом и моим предыдущим (отдельные операторы
require
для каждого модуля)?
Примечание: я принял ответ Дейва Шерохмана, так как он наиболее полно отвечает на вопрос, который я задал. Тем не менее, я в конечном итоге реализовал решение, основанное на ответе лордадмиры.