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

发布于 2024-09-28 11:20:19 字数 444 浏览 0 评论 0 原文

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

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

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

请注意,我不想创建另一个模块来扩展这个模块,这实际上只是为了我想添加的即时内容。

I'm writing a module for a moose object. I would like to allow a user using this object (or myself...) add some fields on the fly as he/she desires. I can't define these fields a priori since I simply don't know what they will be.

I currently simply added a single field called extra of type hashref which is is set to rw, so users can simply put stuff in that hash:

# $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};

This works. But... is this a common practice? Any other (possibly more elegant) ideas?

Note I do not wish to create another module the extends this one, this really just for on-the-fly stuff I'd like to add.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甜中书 2024-10-05 11:20:19

我可能会通过本机特征来做到这一点:

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

此类内容的常见用例是将可选的可自省数据添加到异常和消息类。

I would probably do this via native traits:

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 { {} }

On an object you'd use this like the following:

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

A common use-case for stuff like this is adding optional introspectable data to exception and message classes.

多孤肩上扛 2024-10-05 11:20:19

如果您还没有使类不可变(有一个 性能损失(除了我担心动态更改类定义之外),您应该能够通过获取对象的元类来做到这一点(使用 $meta = $object ->meta) 并使用 add_attribute 方法="noreferrer">类::MOP::类

#!/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

If you haven't made the class immutable (there is a performance penalty for not doing that, in addition to my concerns about changing class definitions on the fly), you should be able to do that by getting the meta class for the object (using $meta = $object->meta) and using the add_attribute method in Class::MOP::Class.

#!/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";

Output:

42
5
﹎☆浅夏丿初晴 2024-10-05 11:20:19

如果您想向对象而不是整个类添加方法,请查看类似 MooseX::SingletonMethod

例如

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

而且这篇博客文章可能有用并且/或兴趣:简单匿名对象

/I3az/

Just in case you want to add a method to an object and not to the whole class then have a look at something like 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!

So in above the method baz is only added to the object $foo and not to class Foo.

Hmmm... I wonder if I could implement a MooseX::SingletonAttribute?

Some previous SO answer using MooseX::SingletonMethod:

And also this blog post maybe of use and/or interest: Easy Anonymous Objects

/I3az/

江南月 2024-10-05 11:20:19

即使在运行时修改类不是一个好的做法,您也可以简单地使元类可变,添加属性并再次使类不可变:

 $ref->meta->make_mutable ;
 $ref->meta->add_attribute($attr_name,%cfg) ;
 $ref->meta->make_immmutable ;

Even if it's not a good pratice to modify a class at runtime, you can simply make the meta-class mutable, add the attribute(s) and make class immutable again:

 $ref->meta->make_mutable ;
 $ref->meta->add_attribute($attr_name,%cfg) ;
 $ref->meta->make_immmutable ;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文