The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

MooseX::DataModel - Create object models from datastructures

SYNOPSIS

  package MyModel {
    use MooseX::DataModel;

    version => (isa => 'Int');
    description => (isa => 'Str', required => 1);

    sub do_something {
      my $self = shift;
      if(shift->version == 3) ... 
    }
    # Moose is imported for your convenience 
    has foo => (...);
  }

  my $obj = MyModel->MooseX::DataModel::new_from_json('{"version":3,"description":"a json document"}');
  # $obj is just a plain old Moose object
  print $obj->version;

  my $obj = MyModel->new({ version => 6, description => 'A description' });
  $obj->do_something;

DESCRIPTION

Working with "plain datastructures" (nested hashrefs, arrayrefs and scalars) that come from other systems can be a pain.

Normally those datastructures are not arbitrary: they have some structure to them: most of them come to express "object like" things. MooseX::DataModel tries to make converting these datastructures into objects in an easy, declarative fashion.

Lots of times

MooseX::DataModel also helps you validate the datastructures. If you get an object back, it conforms to your object model. So if you declare a required key, and the passed datastructure doesn't contain it: you will get an exception. If the type of the key passed is different from the one declared: you get an exception. The advantage over using a JSON validator, is that after validation you still have your original datastructure. With MooseX::DataModel you get full-blown objects, to which you can attach logic.

USAGE

Just use MooseX::DataModel in a class. It will import three keywords key, array, object. With these keywords we can specify attributes in our class

key attribute => (isa => $type, [required => 1, location => $location])

Declares an attribute named "attribute" that is of type $type. $type can be a string with a Moose type constraint (Str, Int), or any user defined subtype (MyPositiveInt). Also it can be the name of a class. If it's a class, MooseX::DataModel will coerce a HashRef to the specified class (using the HashRef as the objects' constructor parameters).

  package VersionObject {
    use MooseX::DataModel;
    key major => (isa => 'Int');
    key minor => (isa => 'Int');
  }
  package MyObject {
    use MooseX::DataModel;
    key version => (isa => 'VersionObject');
  }

  my $o = MyObject->MooseX::DataModel::new_from_json('{"version":{"major":3,"minor":5}}');
  # $o->version->isa('VersionObject') == true
  print $o->version->major;
  # prints 3
  print $o->version->minor;
  # prints 5

required => 1: declare that this attribute is obliged to be set in the passed datastructure

  package MyObject {
    use MooseX::DataModel;
    key version => (isa => 'Int', required => 1);
  }
  my $o = MyObject->MooseX::DataModel::new_from_json('{"document_version":3}');
  # exception, since "version" doesn't exist
  
  my $o = MyObject->MooseX::DataModel::new_from_json('{"version":3}');
  print $o->version;
  # prints 3

location => $location: $location is a string that specifies in what key of the datastructure to find the attributes' value:

  package MyObject {
    use MooseX::DataModel;
    key Version => (isa => 'Int', location => 'document_version');
  }
  my $o = MyObject->MooseX::DataModel::new_from_json('{"document_version":3}');
  print $o->Version;
  # prints 3

array attribute => (isa => $type, [required => 1, location => $location])

Declares an attribute that holds an array whose elements are of a certain type.

$type, required and location work as in "key"

  package MyObject {
    use MooseX::DataModel;
    key name => (isa => 'Str', required => 1);
    array likes => (isa => 'Str', required => 1, location => 'his_tastes');
  }
  my $o = MyObject->MooseX::DataModel::new_from_json('{"name":"pplu":"his_tastes":["cars","ice cream"]}");
  print $o->likes->[0];
  # prints 'cars'

object attribute => (isa => $type, [required => 1, location => $location])

Declares an attribute that holds an hash ("JS object") whose elements are of a certain type. This is useful when in the datastructure you have a hash with arbitrary keys (for known keys you would describe an object with the "key" keyword.

$type, required and location work as in "key"

  package MyObject {
    use MooseX::DataModel;
    key name => (isa => 'Str', required => 1);
    object likes => (isa => 'Int', required => 1, location => 'his_tastes');
  }
  my $o = MyObject->MooseX::DataModel::new_from_json('{"name":"pplu":"his_tastes":{"cars":9,"ice cream":6}}");
  print $o->likes->{ cars };
  # prints 9

METHODS

new

Your class gets the default Moose constructor. You can pass it a hashref with the datastructure

  my $o = MyObject->new({ name => 'pplu', his_tastes => { cars => 9, 'ice cream' => 6 }});

MooseX::DataModel::from_json

There is a convenience constructor for parsing a JSON (so you don't have to do it from the outside)

  my $o = MyObject->MooseX::DataModel::from_json("JSON STRING");

INNER WORKINGS

All this can be done with plain Moose, using subtypes, coercions and declaring the appropiate attributes (that's what really happens on the inside, although it's not guaranteed to stay that way forever). MooseX::DataModel just wants to help you write less code :)

BUGS and SOURCE

The source code is located here: https://github.com/pplu/moosex-datamodel

Please report bugs to:

COPYRIGHT and LICENSE

    Copyright (c) 2015 by CAPSiDE

    This code is distributed under the Apache 2 License. The full text of the license can be found in the LICENSE file included with this module.