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";
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)
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)).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With