Further to that, here's the Moose example reworked to use MooseX::Role::Parameterized; this factors out the grid-related logic into a role, to make it easier to create classes that are a grid of Cell objects, or a grid of strings, or a grid of filehandles, or whatever...
use v5.14;
package Cell {
use Moose;
use Types::Standard -types;
has name => (is => 'rw', isa => Str);
sub from_name {
my $class = shift;
$class->new(name => @_);
}
__PACKAGE__->meta->make_immutable;
}
package Grid {
use MooseX::Role::Parameterized;
use List::Objects::Types -types;
use Types::TypeTiny qw( TypeTiny );
parameter type_constraint => (isa => TypeTiny, required => 1);
role {
my $p = shift;
has cells => (
is => 'ro',
isa => TypedArray[TypedArray[ $p->type_constraint ]],
coerce => 1,
handles => {
get_row => 'get',
set_row => 'set',
all_rows => 'all',
add_row => 'push',
},
);
method get_cell => sub {
my $self = shift;
my ($row, $col) = @_;
$self->get_row($row)->get($col);
};
method set_cell => sub {
my $self = shift;
my ($row, $col, $value) = @_;
$self->get_row($row)->set($col, $value);
};
method all_cells => sub {
my $self = shift;
map { $_->all } $self->all_rows;
};
method get_col => sub {
my $self = shift;
my ($col) = @_;
map { $_->get($col) } $self->all_rows;
};
method set_col => sub {
my $self = shift;
my ($col, $values) = @_;
my @rows = $self->all_rows;
for my $i (0 .. $#rows) {
$rows[$i]->set($col) = $values->[$i];
}
};
method add_col => sub {
my $self = shift;
my ($values) = @_;
my @rows = $self->all_rows;
for my $i (0 .. $#rows) {
$rows[$i]->push($values->[$i]);
}
};
method all_cols => sub {
my $self = shift;
my $col_count = $self->get_row(0)->count;
my $return_type = TypedArray[$p->type_constraint];
return
map { $return_type->coerce($_); }
map { [ $self->get_col($_) ]; }
0 .. $col_count-1;
};
}
}
package CellGrid {
use Moose;
use Types::Standard -types;
with Grid => {
type_constraint => (InstanceOf['Cell'])->plus_constructors(Str
+, 'from_name')
};
sub to_string {
my $self = shift;
join "\n", map(join("\t", map($_->name, $_->all)), $self->all_
+rows);
}
__PACKAGE__->meta->make_immutable;
}
my $grid = CellGrid->new(
cells => [
[ 'foo1', 'bar1' ],
[ 'foo2', 'bar2' ],
]
);
$grid->add_col(['baz1', 'baz2']);
$grid->get_cell(1, 1)->name('QUUX');
say $grid->to_string;
__END__
foo1 bar1 baz1
foo2 QUUX baz2
I really need to add some sugar for parameterized roles to Moops. :-)