#!/usr/bin/perl -w use Modern::Perl '2011'; { package Cell; use Moose; has 'name' => ( is => 'rw', isa => 'Str', default => '', ); no Moose; __PACKAGE__->meta->make_immutable; } { package Row; use Moose; use Moose::Util::TypeConstraints; has 'row' => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[Cell]', required => 1, default => sub { [] }, handles => { pushCell => 'push', getCell => 'get', allCells => 'elements', }, ); sub toString { my $self = shift; join "\t", map($_->name, $self->allCells); } no Moose; no Moose::Util::TypeConstraints; __PACKAGE__->meta->make_immutable; } { package Grid;; use Moose; use Moose::Util::TypeConstraints; # coerce an 'ArrayRef[ArrayRef[Cell]]' struct provided by the caller into an 'ArrayRef[Row]' type subtype 'A::Row' => as 'ArrayRef[Row]'; coerce 'A::Row' => from 'ArrayRef[ArrayRef[Cell]]' => via { [ map {Row->new( row => $_ )} @$_ ] }; # coerce an 'ArrayRef[Cell]' struct provided by the caller into a 'Row' type coerce 'Row' => from 'ArrayRef[Cell]' => via { Row->new( row => $_ ) }; has 'grid' => ( traits => ['Array'], is => 'ro', isa => 'A::Row', required => 1, default => sub { [] }, coerce => 1, handles => { addRow => 'push', getRow => 'get', allRows => 'elements', }, ); sub addCell { my ($self, $index, @cells) = @_; $self->addRow( [] ) if !defined $self->getRow($index); $self->getRow($index)->pushCell(@cells); } sub toString { my $self = shift; join "\n", map {join "\t", map($_->name, $_->allCells)} $self->allRows; } no Moose; no Moose::Util::TypeConstraints; __PACKAGE__->meta->make_immutable; } use strict; ################## ### Test Cases ### ################## # testing Row class #CASE #1: create a new instance by first building a row (reference to an array), and then passing this to the constructor print "BEGIN row1 test\n"; my $row; for my $y ("A" .. "E") { my $mycell = Cell->new( name => "${y}0" ); push @$row, $mycell; } my $row1 = Row->new( row => $row ); print $row1->toString . "\n"; my $mycell = Cell->new( name => "F0" ); $row1->pushCell($mycell); print $row1->toString . "\n"; #$row1->pushCell( q/Whammi/ ); #print $row1->toString . "\n"; print "END row1 test\n\n"; #CASE #2: create a new empty instance of a row, then add new elements individually. print "BEGIN row2 test\n"; my $row2 = Row->new; for my $y ("A" .. "E") { my $mycell = Cell->new( name => "${y}0" ); $row2->pushCell($mycell); } print $row2->toString . "\n"; #$row2->pushCell( q/Whammi/ ); #print $row2->toString . "\n"; print "END row2 test\n\n"; # testing Grid class #CASE #1A: create a new Grid instance by first building an array of Row structs, and then passing this to the constructor (as a reference) print "BEGIN grid1A test\n"; my $struct1A; #my @struct1A; # both of these methods work for my $x (0 .. 4) { my $rowRef; for my $y ("A" .. "E") { my $mycell = Cell->new( name => "$y$x" ); push @$rowRef, $mycell; } my $row = Row->new( row => $rowRef ); push @$struct1A, $row; #push @struct1A, $row; } my $grid1A = Grid->new( grid => $struct1A ); #my $grid1A = Grid->new( grid => \@struct1A ); print $grid1A->toString . "\n"; print "\n"; my $mycell1A = Cell->new( name => "F3" ); $grid1A->addCell(3, $mycell1A); print $grid1A->toString . "\n"; #$grid1A->addCell(3, q/Whammi/); #print $grid1A->toString . "\n"; print "END grid1A test\n\n"; #CASE #1B: create a new Grid instance by first building a 2d-array of Cell structs, and then passing this to the constructor (as a reference) :: coercion needs to be working for this to succeed print "BEGIN grid1B test\n"; #my $struct1B; my @struct1B; #both methods work for my $x (0 .. 4) { for my $y ("A" .. "E") { my $mycell = Cell->new( name => "$y$x" ); #push @{$$struct1B[$x]}, $mycell; # yikes! that's pretty scary! Builds an array-of-arrays-of-Cells as a reference push @{$struct1B[$x]}, $mycell; } } #my $grid1B = Grid->new( grid => $struct1B ); my $grid1B = Grid->new( grid => \@struct1B ); print $grid1B->toString . "\n"; print "\n"; my $mycell1B = Cell->new( name => "F3" ); $grid1B->addCell(3, $mycell1B); print $grid1B->toString . "\n"; #$grid1B->addCell(3, q/Whammi/); #print $grid1B->toString . "\n"; print "END grid1B test\n\n"; #CASE #2A: create a new empty Grid instance, then add new rows individually as Row structs. print "BEGIN grid2A test\n"; my $grid2A = Grid->new; for my $x (0 .. 4) { #my $rowRef; my @row; # both of these methods work as well for my $y ("A" .. "E") { my $mycell = Cell->new( name => "$y$x" ); #push @$rowRef, $mycell; push @row, $mycell; } #my $row = Row->new( row => $rowRef ); my $row = Row->new( row => \@row ); $grid2A->addRow( $row ); } print $grid2A->toString . "\n"; print "\n"; my $mycell2A = Cell->new( name => "F3" ); $grid2A->addCell(3, $mycell2A); print $grid2A->toString . "\n"; #$grid2A->addCell(3, q/Whammi/); #print $grid2A->toString . "\n"; print "END grid2A test\n\n"; #CASE #2B: create a new empty Grid instance, then add new rows individually as an array of Cell structs :: coercion needs to be working for this to succeed print "BEGIN grid2B test\n"; my $grid2B = Grid->new; for my $x (0 .. 4) { #my $rowRef; my @row; # both of these methods work for my $y ("A" .. "E") { my $mycell = Cell->new( name => "$y$x" ); #push @$rowRef, $mycell; push @row, $mycell; } $grid2B->addRow( \@row ); #$grid2B->addRow( $rowRef ); } print $grid2B->toString . "\n"; print "\n"; my $mycell2B = Cell->new( name => "F3" ); $grid2B->addCell(3, $mycell2B); print $grid2B->toString . "\n"; #$grid2B->addCell(3, q/Whammi/); #print $grid2B->toString . "\n"; print "END grid2B test\n\n"; #CASE #3: create a new empty Grid instance, then add new rows individually as an array of Cell structs :: coercion needs to be working for this to succeed #this differs from CASE 2B in that I am constructing an anonymous array in one expression, rather than pushing the elements one-by-one onto the anon array. print "BEGIN grid3 test\n"; my $grid3 = Grid->new; my $o1 = Cell->new( name => 'X1' ); my $o2 = Cell->new( name => 'Y1' ); my $o3 = Cell->new( name => 'Z1' ); $grid3->addRow([$o1, $o2, $o3]); print $grid3->toString . "\n"; my $o4 = Cell->new( name => 'W1' ); $grid3->addCell(0, $o4); print $grid3->toString . "\n"; #$grid3->addRow( qw/Whammi1 Whammi2/ ); #print $grid3->toString . "\n"; print "END grid3 test\n\n"; #CASE #4: last case; create a new empty Grid instance, then add each cell one-by-one print "BEGIN grid4 test\n"; my $grid4 = Grid->new; for my $x (0 .. 4) { for my $y ("A" .. "E") { my $mycell = Cell->new( name => "$y$x" ); $grid4->addCell($x, $mycell); } } print $grid4->toString . "\n"; print "\n"; my $mycell4A = Cell->new( name => "F3" ); $grid4->addCell(3, $mycell4A); print $grid4->toString . "\n"; print "\n"; my $mycell4B = Cell->new( name => "A5" ); $grid4->addCell(5, $mycell4B); print $grid4->toString . "\n"; print "END grid4 test\n\n";