我有一个Moose :: Role,它包含一个网络客户端作为属性:
package Widget;
use Moose::Role;
has 'network_thingy' => (
isa => Maybe[ThingyClient],
);
当然,我有几个具体的Moose类使用这个角色:
package BlueWidget;
use Moose;
with 'Widget';
现在谈到Widgets的功能测试。我们有能力创建ThingyServer
个对象,直接使用ThingyServer对象而不是旋转守护进程并让ThingyClient通过网络连接它会更快更好。因为ThingyClient& ThingyServer方便地使用完全相同的方法,这应该很容易实现。但是当然,当测试最终构建一个BlueWidget时,Moose要求我使用ThingyClient。
我做了一些研究,并且遇到了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角色的属性?
答案 0 :(得分:2)
当一个类使用角色时,属性会从角色复制到该类。如果您随后更改了角色中的属性,则该类中的副本不受影响。
因此,您需要遍历已经使用该角色的类,并更改每个类中的属性。 Moose :: Meta :: Role中有一个consumers
方法可以帮助您获取已经消耗该角色的类列表,但是它只涵盖直接消耗该角色的类,而不是说,那些的子类。
如果类已经变为不可变(__PACKAGE__->meta->make_immutable
),则在修改属性之前,您需要再次使它们可变。
总的来说,改变角色模块(即编辑文件)可能是个更好的主意;不要尝试在运行时调整属性。也许将isa
设置为duck_type类型约束?