【问题标题】:Modifying attributes of a Moose::Role at runtime在运行时修改 Moose::Role 的属性
【发布时间】:2013-12-21 05:23:40
【问题描述】:

我有一个 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 要求我在测试最终构建 BlueWidget 时使用 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 角色的属性?

【问题讨论】:

    标签: perl moose mop


    【解决方案1】:

    当一个类使用一个角色时,属性从角色复制到类。如果随后更改角色中的属性,则类中的 copy 不受影响。

    因此,您需要遍历已使用该角色的类,并更改每个类中的属性。 Moose::Meta::Role 中有一个 consumers 方法可以帮助您获取已使用该角色的类的列表,但它仅涵盖直接使用该角色的类,而不是,比如说,那些的子类。

    如果已将类设为不可变 (__PACKAGE__->meta->make_immutable),则需要在修改属性之前再次将它们设为可变。

    总体而言,仅更改角色模块(即编辑文件)可能是一个更好的主意;不要试图在运行时调整属性。也许将isa 设置为duck_type 类型约束?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多