如何灵活地向Moose对象添加数据?

时间:2010-10-22 10:48:58

标签: perl moose

我正在为驼鹿物体写一个模块。我想允许使用此对象的用户(或我自己......)根据需要随时添加一些字段。我无法先验地定义这些字段,因为我根本不知道它们会是什么。

我目前只是添加了一个名为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};

这很有效。但是......这是一种常见的做法吗?还有其他(可能更优雅)的想法吗?

注意我不想创建另一个扩展此模块的模块,这实际上仅适用于我想要添加的实时内容。

4 个答案:

答案 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 ;