Изменение атрибутов Moose::Role во время выполнения
У меня есть Moose::Role, который содержит сетевой клиент в качестве атрибута:
package Widget;
use Moose::Role;
has 'network_thingy' => (
isa => Maybe[ThingyClient],
);
И, конечно, у меня есть пара конкретных классов Moose, которые используют эту роль:
package BlueWidget;
use Moose;
with 'Widget';
Теперь речь идет о функциональном тестировании виджетов. У нас есть возможность создавать ThingyServer
объектов, и было бы намного быстрее и в целом превосходно напрямую использовать объекты ThingyServer вместо того, чтобы раскручивать демон и подключать к нему ThingyClient по сети. Поскольку ThingyClient и ThingyServer удобно использовать одинаковые методы, это должно быть легко возможно. Но, конечно же, Moose требует, чтобы я использовал ThingyClient, когда тест в конечном итоге создает BlueWidget.
Я провел небольшое исследование и наткнулся на документацию Moose::Meta. Казалось идеальным! Итак, вот код теста:
my $metarole = Moose::Meta::Role->initialize('Widget');
// first remove the old attribute
$metarole->remove_attribute('network_thingy');
Я собирался добавить новый атрибут, но я подумал, что сначала проверю состояние роли и класса. Теперь, если я выкину $ metarole, это выглядит великолепно. Больше нет атрибута network_thingy. Но если я создам класс BlueWidget или просто вернусь в метакласс...
$metaclass = Moose::Meta::Class->initialize('BlueWidget');
diag Dumper ($metaclass);
... конечно network_thingy
все еще там. Это совсем не то, что я ожидал. Как я могу изменить / удалить / заменить атрибут роли Widget во время выполнения?
1 ответ
Когда класс потребляет роль, атрибуты копируются из роли в класс. Если вы затем измените атрибут в роли, копия в классе не изменится.
Таким образом, вам нужно будет пройтись по классам, которые использовали роль, и изменить атрибут в каждом классе. Есть consumers
метод в Moose::Meta::Role, который может помочь вам получить список классов, которые использовали роль, однако он охватывает только классы, которые непосредственно использовали роль, а не, скажем, их подклассы.
Если классы были сделаны неизменяемыми (__PACKAGE__->meta->make_immutable
), вам нужно снова сделать их изменяемыми, прежде чем изменять атрибут.
В целом, вероятно, лучше всего изменить модуль ролей (т.е. отредактировать файл); не пытайтесь настроить атрибут во время выполнения. Может быть установлен isa
ограничение типа duck_type?