我正在为驼鹿物体写一个模块。我想允许使用此对象的用户(或我自己......)根据需要随时添加一些字段。我无法先验地定义这些字段,因为我根本不知道它们会是什么。
我目前只是添加了一个名为extra的hashref字段,它被设置为rw
,因此用户可以简单地将内容放入该哈希值中:
# $obj is a ref to my Moose object
$obj->extra()->{new_thingie}="abc123"; # adds some arbitrary stuff to the object
say $obj->extra()->{new_thingie};
这很有效。但是......这是一种常见的做法吗?还有其他(可能更优雅)的想法吗?
注意我不想创建另一个扩展此模块的模块,这实际上仅适用于我想要添加的实时内容。
答案 0 :(得分:6)
我可能会通过本地特征来做到这一点:
has custom_fields => (
traits => [qw( Hash )],
isa => 'HashRef',
builder => '_build_custom_fields',
handles => {
custom_field => 'accessor',
has_custom_field => 'exists',
custom_fields => 'keys',
has_custom_fields => 'count',
delete_custom_field => 'delete',
},
);
sub _build_custom_fields { {} }
在对象上,您可以使用以下内容:
my $val = $obj->custom_field('foo'); # get field value
$obj->custom_field('foo', 23); # set field to value
$obj->has_custom_field('foo'); # does a specific field exist?
$obj->has_custom_fields; # are there any fields?
my @names = $obj->custom_fields; # what fields are there?
my $value = $obj->delete_custom_field('foo'); # remove field value
这样的事情的一个常见用例是向异常和消息类添加可选的内省数据。
答案 1 :(得分:5)
如果你没有使类不可变(有performance penalty没有这样做,除了我担心动态更改类定义),你应该能够通过获取对象的元类(使用$meta = $object->meta
)并使用Class::MOP::Class中的add_attribute
方法。
#!/usr/bin/perl
package My::Class;
use Moose;
use namespace::autoclean;
package main;
my $x = My::Class->new;
my $meta = $x->meta;
$meta->add_attribute(
foo => (
accessor => 'foo',
)
);
$x->foo(42);
print $x->foo, "\n";
my $y = My::Class->new({ foo => 5 });
print $y->foo, "\n";
输出:
42 5
答案 2 :(得分:3)
如果您想要将方法添加到对象而不是整个类,那么请查看MooseX::SingletonMethod
之类的内容。
E.g。
use 5.012;
use warnings;
{
package Foo;
use MooseX::SingletonMethod;
sub bar { 'bar' } # method available to all objects
}
my $foo = Foo->new;
$foo->add_singleton_method( baz => sub { 'baz!' } );
$foo->baz; # => baz!
因此,在上面,方法baz
只会添加到对象$foo
而不会添加到类Foo
。
嗯......我想知道我是否可以实现MooseX :: SingletonAttribute?
以前的一些SO回答使用MooseX::SingletonMethod
:
此博客文章也许有用和/或有趣:Easy Anonymous Objects
/ I3az /
答案 3 :(得分:0)
即使在运行时修改类不是一个好习惯,您也可以简单地使元类可变,添加属性并再次使类不可变:
$ref->meta->make_mutable ;
$ref->meta->add_attribute($attr_name,%cfg) ;
$ref->meta->make_immmutable ;