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 )