Moose: How to get an array of objects? Traits?

扶醉桌前 提交于 2019-12-07 05:32:03

问题


I'm beginning to realize that this is for beginners:

package Bad;

has 'arr' => ( is => 'rw', 'ArrayRef[Str]' );

package main;

my $bad = Bad->new(arr => [ "foo", "bar" ]);
print $bad->arr->[0], "\n";

Enter traits. I'm underwhelmed by the traits API, though. Have I misunderstood something? Can I get this API instead somehow? :

print $bad->arr->get(0), "\n";

Details

Review the canonical traits example from Moose::Meta::Attribute::Native::Trait::Array

package Stuff;
use Moose;

has 'options' => (
    traits  => ['Array'],
    is      => 'ro',
    isa     => 'ArrayRef[Str]',
    default => sub { [] },
    handles => {
        all_options    => 'elements',
        add_option     => 'push',
        map_options    => 'map',
        filter_options => 'grep',
        find_option    => 'first',
        get_option     => 'get',
        join_options   => 'join',
        count_options  => 'count',
        has_options    => 'count',
        has_no_options => 'is_empty',
        sorted_options => 'sort',
    },
);

no Moose;
1;

An object declared like that is used e.g.:

my $option = $stuff->get_option(1);

I really don't like that for one array attribute I get and have to manually name 11 methods in my Stuff class - one for every single operation that one can do to 'options'. Inconsistent naming is bound to happen and it is bloaty.

How do I instead (elegantly) get an API like:

my $option = $stuff->options->get(1);

Where all the methods from Moose::Meta::Attribute::Native::Trait::Array are implemented in a type-safe way?

Then all the operations on every single Array are named in exactly the same way...

(I'm actually using Mouse, but most of Mouse is identical to Moose)


回答1:


I think that the best way to get your API into that format would be to create a new object for the options, and delegate the methods into it directly. Something like:

package Stuff;
use Moose;
use Stuff::Options;

has 'options' => (
    'is'      => "ro",
    'isa'     => "Stuff::Options",
    'default' => sub { Stuff::Options->new },
);

no Moose;
1;

And then in Stuff/Options.pm:

package Stuff::Options;
use Moose;

has '_options' => (
    'is'      => "ro",
    'isa'     => "ArrayRef[Str]",
    'traits'  => [ "Array" ],
    'default' => sub { [] },
    'handles' => [ qw(elements push map grep first get join count is_empty sort) ],
);

no Moose;
1;

This would allow code as in your example to work ($stuff->options->get(1)).



来源:https://stackoverflow.com/questions/28094959/moose-how-to-get-an-array-of-objects-traits

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!