How can I flexibly add data to Moose objects?

后端 未结 4 1292
野性不改
野性不改 2020-12-17 00:30

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 f

相关标签:
4条回答
  • 2020-12-17 00:55

    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:

    • How do you replace a method of a Moose object at runtime?
    • How do I make a new Moose class and instantiate an object of that class at runtime?

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

    /I3az/

    0 讨论(0)
  • 2020-12-17 00:56

    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
    0 讨论(0)
  • 2020-12-17 00:57

    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 ;
    
    0 讨论(0)
  • 2020-12-17 01:04

    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.

    0 讨论(0)
提交回复
热议问题