Псевдоним пакета для включения пространств имен двойного использования - PullRequest
3 голосов
/ 08 февраля 2011

У меня интересная ситуация.В некотором (большом) унаследованном коде есть пространство имен, которое должно выглядеть как require A::B, но вместо этого был добавлен путь к A, поэтому можно просто сказать require B.Тем не менее, я хотел бы иметь возможность использовать оба вызова.Возможно ли это без создания перенаправляющего пакета?Например, есть ли способ двойного объявления пакета?

Спасибо!

Ответы [ 3 ]

16 голосов
/ 08 февраля 2011

Сначала загрузите пакет:

require A::B;

Затем псевдоним B до A::B:

*B:: = *A::B::;

Затем скажите require, что он уже загружен B

$INC{'B.pm'}++;

Чтобы убедиться, что все работает правильно, лучше всего выполнить следующие действия внутри блока BEGIN:

BEGIN {
    require A::B;
    *B:: = *A::B::;
    $INC{'B.pm'}++;
}

После этого все require A::B; и require B;линии станут неактивными.Вы также сможете ссылаться на переменные в этом пакете с любым именем.\&A::B::foo == \&B::foo

Чтобы это работало прозрачно, вы можете добавить следующий код в каждый файл:

  • A/B.pm

    *B:: = *A::B::;
    $INC{'B.pm'}++;
    
  • B.pm

    *A::B:: = *B::;
    $INC{'A/B.pm'}++;
    

Тогда, если пользователь делает require A::B;, он может позвонить A::B::foo или B::foo и require B; станет нет-оп.

И если пользователь делает require B;, он может позвонить A::B::foo или B::foo и require A::B; станет неактивным.

Но для удобства обслуживания этовероятно, лучше всего хранить весь реальный код в одном файле (вместе с кодом псевдонимов, приведенным выше), и настроить другой файл как шим, который просто загружает реальный файл.Предполагая, что A/B.pm содержит реальный код:

  • A/B.pm

    *B:: = *A::B::;  # this gets added to the existing file
    $INC{'B.pm'}++;
    
  • B.pm

    require A::B;  # this is the entire file
    
2 голосов
/ 08 февраля 2011

require Something будет искать в каталогах в @INC файл с именем Something.pm.Чтобы получить some-path/A/B.pm для загрузки либо require B, либо require A::B, вам необходимо иметь и some-path, и some-path/A в списке @INC каталога.

Есть множество способов добавить каталоги или иным образом манипулировать списком @INC.

1 голос
/ 08 февраля 2011

Решение Эрика сработало бы, но, честно говоря, я бы застрелил любого, кто сделал это, в реальном производственном коде.Вероятно, вы могли бы достичь аналогичных результатов, используя методы в Package :: Stash , но опять же, зачем так портить таблицу символов?Я бы предпочел исправить устаревший код, который называл вещи неправильно.Серьезно, насколько сложно выполнить поиск и замену в вашем коде и исправить имена пакетов?

Еще один быстрый и грязный способ получить require B; для фактического поиска пакета A :: B - простосоздайте в каталоге lib / символическую ссылку, указывающую на A / B.pm:

cd lib
ln -sf -T A/B.pm B.pm

Обратите внимание, что это создаст два пакета с идентичным кодом, поэтому переменные в одном будут значение не должно совпадать с другим: $A::B::foo будет полностью отделено от $B::foo, даже если их объявление поступит из того же файла.

...