Array-To-Moose
view release on metacpan or search on metacpan
lib/Array/To/Moose.pm view on Meta::CPAN
next if $simple_types{$constraint};
$msg = "$msg has type '$constraint', but your descriptor had '$attrib => "
. $attribs->{$attrib} . "'.";
$msg .= " (Did you forget the '[]' brackets?)"
if $constraint =~ /^ArrayRef/;
croak $msg;
}
}
} # end of local block
1;
__END__
=head1 NAME
Array::To::Moose - Build Moose objects from a data array
=head1 VERSION
This document describes Array::To::Moose version 0.0.9
=head1 SYNOPSIS
use Array::To::Moose;
# or
use Array::To::Moose qw(array_to_moose set_class_ind set_key_ind
throw_nonunique_keys throw_multiple_rows );
C<Array::To::Moose> exports function C<array_to_moose()> by default, and
convenience functions C<set_class_ind()>, C<set_key_ind()>,
C<throw_nonunique_keys()> and C<throw_multiple_rows()> if requested.
=head2 array_to_moose
C<array_to_moose()> builds Moose objects from suitably-sorted
2-dimensional arrays of data of the type returned by, e.g.,
L<DBI::selectall_arrayref()|DBI/selectall_arrayref>
i.e. a reference to an array containing
references to an array for each row of data fetched.
=head2 Example 1a
package Car;
use Moose;
has 'make' => (is => 'ro', isa => 'Str');
has 'model' => (is => 'ro', isa => 'Str');
has 'year' => (is => 'ro', isa => 'Int');
package CarOwner;
use Moose;
has 'last' => (is => 'ro', isa => 'Str');
has 'first' => (is => 'ro', isa => 'Str');
has 'Cars' => (is => 'ro', isa => ArrayRef[Car]');
...
# in package main:
use Array::To::Moose;
# In this dataset Alex owns two cars, Jim one, and Alice three
my $data = [
[ qw( Green Alex Ford Focus 2011 ) ],
[ qw( Green Alex VW Jetta 2009 ) ],
[ qw( Green Jim Honda Civic 2007 ) ],
[ qw( Smith Alice Buick Regal 2012 ) ],
[ qw( Smith Alice Toyota Camry 2008 ) ],
[ qw( Smith Alice BMW X5 2010 ) ],
];
my $CarOwners = array_to_moose(
data => $data,
desc => {
class => 'CarOwner',
last => 0,
first => 1,
Cars => {
class => 'Car',
make => 2,
model => 3,
year => 4,
} # Cars
} # Car Owners
);
print $CarOwners->[2]->Cars->[1]->model; # prints "Camry"
=head2 Example 1b - Hash(ref) Sub-objects
In the above example, C<array_to_moose()> returns a reference to an
B<array> of C<CarOwner> objects, C<$CarOwners>.
If a B<hash> of C<CarOwner> objects is required, a "C<key =E<gt>>... " entry
must be added to the descriptor hash. For example, to construct a hash of
C<CarOwner> objects, whose key is the owner's first name, (unique for
every person in the example data), the call
becomes:
my $CarOwnersH = array_to_moose(
data => $data,
desc => {
class => 'CarOwner',
key => 1, # note key
last => 0,
first => 1,
Cars => {
class => 'Car',
make => 2,
model => 3,
year => 4,
} # Cars
} # Car Owners
);
print $CarOwnersH->{Alex}->Cars->[0]->make; # prints "Ford"
Similarly, to construct the C<Cars> sub-objects as I<hash> sub-objects
(and not an I<array> as above), define C<CarOwner> as:
package CarOwner;
use Moose;
has 'last' => (is => 'ro', isa => 'Str' );
has 'first' => (is => 'ro', isa => 'Str' );
has 'Cars' => (is => 'ro', isa => 'HashRef[Car]'); # Was 'ArrayRef[Car]'
and noting that the car C<make> is unique for each person in the C<$data> dataset, we
construct the reference to an array of objects with the call:
$CarOwners = array_to_moose(
data => $data,
desc => {
class => 'CarOwner',
last => 0,
first => 1,
Cars => {
class => 'Car',
key => 2, # note key
model => 3,
year => 4,
} # Cars
} # Car Owners
);
print $CarOwners->[2]->Cars->{BMW}->model; # prints 'X5'
=head2 Example 1c - "Simple" Reference Attributes
If, instead of the car owner object containing an ArrayRef or HashRef of
C<Car> sub-objects, it contains, say, a ArrayRef of strings representing the
names of the car makers:
package SimpleCarOwner;
use Moose;
has 'last' => (is => 'ro', isa => 'Str' );
has 'first' => (is => 'ro', isa => 'Str' );
has 'CarMakers' => (is => 'ro', isa => 'ArrayRef[Str]');
Using the same dataset from Example 1a, we construct an arrayref
C<SimpleCarOwner> objects as:
$SimpleCarOwners = array_to_moose(
data => $data,
desc => {
class => 'SimpleCarOwner',
last => 0,
first => 1,
CarMakers => [2], # Note the '[...]' brackets
}
);
print $SimpleCarOwners->[2]->[1]; # prints 'Toyota'
I.e., when the object attribute is an I<ArrayRef> of one of the Moose "simple" types,
e.g. C<'Str'>, C<'Num'>, C<'Bool'>,
etc (See L<Moose::Manual::Types|THE TYPES>), then the column number should
appear in square brackets ('C<CarMakers =E<gt> [2]>' above) to differentiate them from the bare
types (C<last =E<gt> 0,> and C<first =E<gt> 1,> above).
Note that Array::To::Moose doesn't (yet) handle the case of hashrefs of
"simple" types, e.g., C<( isa =E<gt> "HashRef[Str]" )>
=head2 Example 2 - Use with DBI
The main rationale for writing C<Array::To::Moose> is to make it easy to build
Moose objects from data extracted from relational databases,
especially when the database query
involves multiple tables with one-to-many relationships to each other.
As an example, consider a database which models patients making visits
to a clinic on multiple occasions, and on each visit, having a doctor
run some tests and diagnose the patient's complaint. In this model, the
database I<Patient> table would have a one-to-many relationship with the
I<Visit> table, which in turn would have a one-to-many relationship with
the I<Test> table
The corresponding Moose model has nested Moose objects which reflects those
one-to-many relationships, i.e.,
multiple Visit objects per Patient object and multiple Test objects
per Visit object, declared as:
package Test;
use Moose;
has 'name' => (is => 'rw', isa => 'Str');
has 'result' => (is => 'rw', isa => 'Str');
package Visit;
use Moose;
has 'date' => (is => 'rw', isa => 'Str' );
has 'md' => (is => 'rw', isa => 'Str' );
has 'diagnosis' => (is => 'rw', isa => 'Str' );
has 'Tests' => (is => 'rw', isa => 'HashRef[Test]' );
package Patient;
use Moose;
has 'last' => (is => 'rw', isa => 'Str' );
has 'first' => (is => 'rw', isa => 'Str' );
( run in 1.455 second using v1.01-cache-2.11-cpan-39bf76dae61 )