Can I set the "isa" attribute of a Moose object attribute when building?
I have a Moose object with the following attribute:
has 'people' => (
is => 'ro',
isa => 'ArrayRef[Person::Child]',
traits => ['Array'],
default => sub { [] },
handles => {
all_people => 'elements',
get_people => 'get',
push_people => 'push',
pop_people => 'pop',
count_people => 'count',
sort_people => 'sort',
grep_people => 'grep',
},
);
Please note: isaset as "ArrayRef [Person :: Child]".
I would like to be able to choose between Person::Child, Person::Adultetc. when creating my object. Is this possible, or should I create different objects that will be identical except for the isaattribute people?
(This reminds me of Java generics ).
Why not move the definition of this attribute to a role and reuse it, corresponding to parameterization, in other classes?
package MyApp::Thingy::HasPeople;
use MooseX::Role::Parameterized;
parameter person_type => (
isa => 'Str',
required => 1,
);
role {
my $person_type = shift->person_type;
has 'people' => (
is => 'ro',
isa => "ArrayRef[${person_type}]",
traits => ['Array'],
default => sub { [] },
handles => {
all_people => 'elements',
get_people => 'get',
push_people => 'push',
pop_people => 'pop',
count_people => 'count',
sort_people => 'sort',
grep_people => 'grep',
},
);
};
1;
- , ,
package MyApp::Thingy::WithChildren;
use Moose;
with 'MyApp::Thingy::HasPeople' => { person_type => 'Person::Child' };
1;
package MyApp::Thingy::WithAdults;
use Moose;
with 'MyApp::Thingy::HasPeople' => { person_type => 'Person::Adult' };
1;
, , , API-, , , .
ArrayRef, Person::Child, Person::Adult, , , , .
use List::AllUtils 'all';
subtype 'PersonList', as 'ArrayRef', where {
my $class = blessed $_->[0];
$_->[0]->isa('Person') && all { blessed $_ eq $class } @{ $_ };
};
has persons => (
is => 'ro',
isa => 'PersonList',
...,
);
, , , - .
Java, :
package Interfaces::Person;
use Moose::Role;
requires qw( list all attributes or methods that you require );
1;
, Person:: Adult Person:: Child :
package Person::Adult;
...
# add at the end
with qw(Interfaces::Person);
1;
package Person::Child;
...
# add at the end
with qw(Interfaces::Person);
1;
:
package My::People;
use Moose;
use MooseX::Types::Moose qw( ArrayRef );
use MooseX::Types::Implements qw( Implements );
has 'people' => (
is => 'ro',
isa => ArrayRef[Implements[qw(Interfaces::Person)]],
traits => ['Array'],
default => sub { [] },
handles => {
all_people => 'elements',
get_people => 'get',
push_people => 'push',
pop_people => 'pop',
count_people => 'count',
sort_people => 'sort',
grep_people => 'grep',
},
);
"" , :: .