Moved recipes to get rid of Basic 8 as a TODO, and just let them be numbered sequenti...
Dave Rolsky [Sun, 3 May 2009 18:27:07 +0000 (13:27 -0500)]
lib/Moose/Cookbook.pod
lib/Moose/Cookbook/Basics/Recipe10.pod
lib/Moose/Cookbook/Basics/Recipe11.pod
lib/Moose/Cookbook/Basics/Recipe12.pod [deleted file]
lib/Moose/Cookbook/Basics/Recipe8.pod [new file with mode: 0644]
lib/Moose/Cookbook/Basics/Recipe9.pod

index 6163c85..67ccc15 100644 (file)
@@ -58,28 +58,22 @@ the usual method overriding style "inside-out".
 Making a class immutable greatly increases the speed of accessors and
 object construction.
 
-=item L<Moose::Cookbook::Basics::Recipe8> - Managing complex relations with trigger (TODO)
-
-I<abstract goes here>
-
-Work off of this http://code2.0beta.co.uk/moose/svn/Moose/trunk/t/200_examples/007_Child_Parent_attr_inherit.t
-
-=item L<Moose::Cookbook::Basics::Recipe9> - Builder methods and lazy_build
+=item L<Moose::Cookbook::Basics::Recipe8> - Builder methods and lazy_build
 
 The builder feature provides an inheritable and role-composable way to
 provide a default attribute value.
 
-=item L<Moose::Cookbook::Basics::Recipe10> - Operator overloading, subtypes, and coercion
+=item L<Moose::Cookbook::Basics::Recipe9> - Operator overloading, subtypes, and coercion
 
 Demonstrates using operator overloading, coercion, and subtypes to
 model how eye color is determined during reproduction.
 
-=item L<Moose::Cookbook::Basics::Recipe11> - Using BUILDARGS and BUILD to hook into object construction
+=item L<Moose::Cookbook::Basics::Recipe10> - Using BUILDARGS and BUILD to hook into object construction
 
 This recipe demonstrates the use of C<BUILDARGS> and C<BUILD> to hook
 into object construction.
 
-=item L<Moose::Cookbook::Basics::Recipe12> - Extending a non-Moose base class
+=item L<Moose::Cookbook::Basics::Recipe11> - Extending a non-Moose base class
 
 In this recipe, we make a Moose-based subclass of L<DateTime>, a
 module which does not use Moose itself.
index 8cafe18..ecbfc99 100644 (file)
 
 =head1 NAME
 
-Moose::Cookbook::Basics::Recipe10 - Operator overloading, subtypes, and coercion
+Moose::Cookbook::Basics::Recipe11 - Using BUILDARGS and BUILD to hook into object construction
 
 =head1 SYNOPSIS
 
-  package Human;
+  package Person;
 
-  use Moose;
-  use Moose::Util::TypeConstraints;
-
-  subtype 'Gender'
-      => as 'Str'
-      => where { $_ =~ m{^[mf]$}s };
-
-  has 'gender' => ( is => 'ro', isa => 'Gender', required => 1 );
-
-  has 'mother' => ( is => 'ro', isa => 'Human' );
-  has 'father' => ( is => 'ro', isa => 'Human' );
-
-  use overload '+' => \&_overload_add, fallback => 1;
+  has 'ssn' => (
+      is        => 'ro',
+      isa       => 'Str',
+      predicate => 'has_ssn',
+  );
 
-  sub _overload_add {
-      my ( $one, $two ) = @_;
+  has 'country_of_residence' => (
+      is      => 'ro',
+      isa     => 'Str',
+      default => 'usa'
+  );
 
-      die('Only male and female humans may create children')
-          if ( $one->gender() eq $two->gender() );
+  has 'first_name' => (
+      is  => 'ro',
+      isa => 'Str',
+  );
 
-      my ( $mother, $father )
-          = ( $one->gender eq 'f' ? ( $one, $two ) : ( $two, $one ) );
+  has 'last_name' => (
+      is  => 'ro',
+      isa => 'Str',
+  );
 
-      my $gender = 'f';
-      $gender = 'm' if ( rand() >= 0.5 );
+  sub BUILDARGS {
+      my $class = shift;
 
-      return Human->new(
-          gender => $gender,
-          mother => $mother,
-          father => $father,
-      );
+      if ( @_ == 1 && ! ref $_[0] ) {
+          return { ssn => $_[0] };
+      }
+      else {
+          return $class->SUPER::BUILDARGS(@_);
+      }
   }
 
-=head1 DESCRIPTION
-
-This Moose cookbook recipe shows how operator overloading, coercion,
-and sub types can be used to mimic the human reproductive system
-(well, the selection of genes at least).
-
-=head1 INTRODUCTION
-
-Our C<Human> class uses operator overloading to allow us to "add" two
-humans together and produce a child. Our implementation does require
-that the two objects be of opposite genders. Remember, we're talking
-about biological reproduction, not marriage.
-
-While this example works as-is, we can take it a lot further by adding
-genes into the mix. We'll add the two genes that control eye color,
-and use overloading to combine the genes from the parent to model the
-biology.
-
-=head2 What is Operator Overloading?
-
-Overloading is I<not> a Moose-specific feature. It's a general OO
-concept that is implemented in Perl with the C<overload>
-pragma. Overloading lets objects do something sane when used with
-Perl's built in operators, like addition (C<+>) or when used as a
-string.
-
-In this example we overload addition so we can write code like
-C<$child = $mother + $father>.
-
-=head1 GENES
-
-There are many genes which affect eye color, but there are two which
-are most important, I<gey> and I<bey2>. We will start by making a
-class for each gene.
-
-=head2 Human::Gene::bey2
-
-  package Human::Gene::bey2;
-
-  use Moose;
-  use Moose::Util::TypeConstraints;
-
-  type 'bey2_color' => where { $_ =~ m{^(?:brown|blue)$} };
-
-  has 'color' => ( is => 'ro', isa => 'bey2_color' );
-
-This class is trivial, We have a type constraint for the allowed
-colors, and a C<color> attribute.
-
-=head2 Human::Gene::gey
-
-  package Human::Gene::gey;
-
-  use Moose;
-  use Moose::Util::TypeConstraints;
-
-  type 'gey_color' => where { $_ =~ m{^(?:green|blue)$} };
-
-  has 'color' => ( is => 'ro', isa => 'gey_color' );
-
-This is nearly identical to the C<Humane::Gene::bey2> class, except
-that the I<gey> gene allows for different colors.
-
-=head1 EYE COLOR
-
-We could just give add four attributes (two of each gene) to the
-C<Human> class, but this is a bit messy. Instead, we'll abstract the
-genes into a container class, C<Human::EyeColor>. Then a C<Human> can
-have a single C<eye_color> attribute.
-
-  package Human::EyeColor;
+  sub BUILD {
+      my $self = shift;
 
-  use Moose;
-  use Moose::Util::TypeConstraints;
-
-  coerce 'Human::Gene::bey2'
-      => from 'Str'
-          => via { Human::Gene::bey2->new( color => $_ ) };
-
-  coerce 'Human::Gene::gey'
-      => from 'Str'
-          => via { Human::Gene::gey->new( color => $_ ) };
-
-  has [qw( bey2_1 bey2_2 )] =>
-      ( is => 'ro', isa => 'Human::Gene::bey2', coerce => 1 );
-
-  has [qw( gey_1 gey_2 )] =>
-      ( is => 'ro', isa => 'Human::Gene::gey', coerce => 1 );
-
-The eye color class has two of each type of gene. We've also created a
-coercion for each class that coerces a string into a new object. Note
-that a coercion will fail if it attempts to coerce a string like
-"indigo", because that is not a valid color for either type of gene.
-
-As an aside, you can see that we can define several identical
-attributes at once by supply an array reference of names as the first
-argument to C<has>.
-
-We also need a method to calculate the actual eye color that results
-from a set of genes. The I<bey2> brown gene is dominant over both blue
-and green. The I<gey> green gene dominant over blue.
-
-  sub color {
-      my ($self) = @_;
-
-      return 'brown'
-          if ( $self->bey2_1->color() eq 'brown'
-          or $self->bey2_2->color() eq 'brown' );
-
-      return 'green'
-          if ( $self->gey_1->color() eq 'green'
-          or $self->gey_2->color() eq 'green' );
-
-      return 'blue';
+      if ( $self->country_of_residence eq 'usa' ) {
+          die 'Cannot create a Person who lives in the USA without an ssn.'
+              unless $self->has_ssn;
+      }
   }
 
-We'd like to be able to treat a C<Human::EyeColor> object as a string,
-so we define a string overloading for the class:
-
-  use overload '""' => \&color, fallback => 1;
-
-Finally, we need to define overloading for addition. That way we can
-add together to C<Human::EyeColor> objects and get a new one with a
-new (genetically correct) eye color.
+=head1 DESCRIPTION
 
-  use overload '+' => \&_overload_add, fallback => 1;
+This recipe demonstrates the use of C<BUILDARGS> and C<BUILD>. By
+defining these methods, we can hook into the object construction
+process without overriding C<new>.
 
-  sub _overload_add {
-      my ( $one, $two ) = @_;
+The C<BUILDARGS> method is called I<before> an object has been
+created. It is called as a class method, and receives all of the
+parameters passed to the C<new> method. It is expected to do something
+with these arguments and return a hash reference. The keys of the hash
+must be attribute C<init_arg>s.
 
-      my $one_bey2 = 'bey2_' . _rand2();
-      my $two_bey2 = 'bey2_' . _rand2();
+The primary purpose of C<BUILDARGS> is to allow a class to accept
+something other than named arguments. In the case of our C<Person>
+class, we are allowing it to be called with a single argument, a
+social security number:
 
-      my $one_gey = 'gey_' . _rand2();
-      my $two_gey = 'gey_' . _rand2();
+  my $person = Person->new('123-45-6789');
 
-      return Human::EyeColor->new(
-          bey2_1 => $one->$one_bey2->color(),
-          bey2_2 => $two->$two_bey2->color(),
-          gey_1  => $one->$one_gey->color(),
-          gey_2  => $two->$two_gey->color(),
-      );
-  }
+The key part of our C<BUILDARGS> is this conditional:
 
-  sub _rand2 {
-      return 1 + int( rand(2) );
-  }
+      if ( @_ == 1 && ! ref $_[0] ) {
+          return { ssn => $_[0] };
+      }
 
-When two eye color objects are added together the C<_overload_add()>
-method will be passed two C<Human::EyeColor> objects. These are the
-left and right side operands for the C<+> operator. This method
-returns a new C<Human::EyeColor> object.
+By default, Moose constructors accept a list of key-value pairs, or a
+hash reference. We need to make sure that C<$_[0]> is not a reference
+before assuming it is a social security number.
 
-=head1 ADDING EYE COLOR TO C<Human>s
+We call C<< $class->SUPER::BUILDARGS(@_) >> to handle all the other
+cases. You should always do this in your own C<BUILDARGS> methods,
+since L<Moose::Object> provides its own C<BUILDARGS> method that
+handles hash references and a list of key-value pairs.
 
-Our original C<Human> class requires just a few changes to incorporate
-our new C<Human::EyeColor> class.
+The C<BUILD> method is called I<after> the object is constructed, but
+before it is returned to the caller. The C<BUILD> method provides an
+opportunity to check the object state as a whole. This is a good place
+to put logic that cannot be expressed as a type constraint on a single
+attribute.
 
-  use List::MoreUtils qw( zip );
+In the C<Person> class, we need to check the relationship between two
+attributes, C<ssn> and C<country_of_residence>. We throw an exception
+if the object is not logically consistent.
 
-  coerce 'Human::EyeColor'
-      => from 'ArrayRef'
-      => via { my @genes = qw( bey2_1 bey2_2 gey_1 gey_2 );
-               return Human::EyeColor->new( zip( @genes, @{$_} ) ); };
+=head1 MORE CONSIDERATIONS
 
-  has 'eye_color' => (
-      is       => 'ro',
-      isa      => 'Human::EyeColor',
-      coerce   => 1,
-      required => 1,
-  );
-
-We also need to modify C<_overload_add()> in the C<Human> class to
-account for eye color:
-
-  return Human->new(
-      gender    => $gender,
-      eye_color => ( $one->eye_color() + $two->eye_color() ),
-      mother    => $mother,
-      father    => $father,
-  );
+This recipe is made significantly simpler because all of the
+attributes are read-only. If the C<country_of_residence> attribute
+were settable, we would need to check that a Person had an C<ssn> if
+the new country was C<usa>. This could be done with a C<before>
+modifier.
 
 =head1 CONCLUSION
 
-The three techniques we used, overloading, subtypes, and coercion,
-combine to provide a powerful interface.
-
-If you'd like to learn more about overloading, please read the
-documentation for the L<overload> pragma.
-
-To see all the code we created together, take a look at
-F<t/000_recipes/basics/010_genes.t>.
-
-=head1 NEXT STEPS
-
-Has this been a real project we'd probably want to:
-
-=over 4
+We have repeatedly discouraged overriding C<new> in Moose
+classes. This recipe shows how you can use C<BUILDARGS> and C<BUILD>
+to hook into object construction without overriding C<new>
 
-=item Better Randomization with Crypt::Random
+The C<BUILDARGS> method lets us expand on Moose's built-in parameter
+handling for constructors. The C<BUILD> method lets us implement
+logical constraints across the whole object after it is created.
 
-=item Characteristic Base Class
-
-=item Mutating Genes
-
-=item More Characteristics
-
-=item Artificial Life
-
-=back
-
-=head1 AUTHORS
-
-Aran Clary Deltac <bluefeet@cpan.org>
+=head1 AUTHOR
 
 Dave Rolsky E<lt>autarch@urth.orgE<gt>
 
-=head1 LICENSE
+=head1 COPYRIGHT AND LICENSE
 
-This work is licensed under a Creative Commons Attribution 3.0 Unported License.
+Copyright 2006-2009 by Infinity Interactive, Inc.
 
-License details are at: L<http://creativecommons.org/licenses/by/3.0/>
+L<http://www.iinteractive.com>
 
-=cut
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
 
+=cut
index ecbfc99..1a44f67 100644 (file)
 
 =pod
 
+=begin testing-SETUP
+
+BEGIN {
+    eval 'use DateTime; use DateTime::Calendar::Mayan;';
+    if ($@) {
+        diag 'DateTime & DateTime::Calendar::Mayan required for this test';
+        ok(1);
+        exit 0;
+    }
+}
+
+=end testing-SETUP
+
 =head1 NAME
 
-Moose::Cookbook::Basics::Recipe11 - Using BUILDARGS and BUILD to hook into object construction
+Moose::Cookbook::Basics::Recipe12 - Extending a non-Moose base class
 
 =head1 SYNOPSIS
 
-  package Person;
+  package My::DateTime;
 
-  has 'ssn' => (
-      is        => 'ro',
-      isa       => 'Str',
-      predicate => 'has_ssn',
-  );
+  use Moose;
+  extends qw( DateTime Moose::Object );
 
-  has 'country_of_residence' => (
-      is      => 'ro',
-      isa     => 'Str',
-      default => 'usa'
-  );
-
-  has 'first_name' => (
-      is  => 'ro',
-      isa => 'Str',
-  );
+  use DateTime::Calendar::Mayan;
 
-  has 'last_name' => (
-      is  => 'ro',
-      isa => 'Str',
+  has 'mayan_date' => (
+      is        => 'ro',
+      isa       => 'DateTime::Calendar::Mayan',
+      init_arg  => undef,
+      lazy      => 1,
+      builder   => '_build_mayan_date',
+      clearer   => '_clear_mayan_date',
+      predicate => 'has_mayan_date',
   );
 
-  sub BUILDARGS {
+  sub new {
       my $class = shift;
 
-      if ( @_ == 1 && ! ref $_[0] ) {
-          return { ssn => $_[0] };
-      }
-      else {
-          return $class->SUPER::BUILDARGS(@_);
-      }
+      my $obj = $class->SUPER::new(@_);
+
+      return $class->meta->new_object(
+          __INSTANCE__ => $obj,
+          @_,
+      );
   }
 
-  sub BUILD {
-      my $self = shift;
+  after 'set' => sub {
+      $_[0]->_clear_mayan_date;
+  };
 
-      if ( $self->country_of_residence eq 'usa' ) {
-          die 'Cannot create a Person who lives in the USA without an ssn.'
-              unless $self->has_ssn;
-      }
+  sub _build_mayan_date {
+      DateTime::Calendar::Mayan->from_object( object => $_[0] );
   }
 
 =head1 DESCRIPTION
 
-This recipe demonstrates the use of C<BUILDARGS> and C<BUILD>. By
-defining these methods, we can hook into the object construction
-process without overriding C<new>.
+This recipe demonstrates how to use Moose to subclass a parent which
+is not Moose based. This recipe only works if the parent class uses a
+blessed hash reference for object instances. If your parent is doing
+something funkier, you should check out L<MooseX::InsideOut>.
 
-The C<BUILDARGS> method is called I<before> an object has been
-created. It is called as a class method, and receives all of the
-parameters passed to the C<new> method. It is expected to do something
-with these arguments and return a hash reference. The keys of the hash
-must be attribute C<init_arg>s.
+You might also want to check out L<MooseX::NonMoose>, which does all
+the grunt work for you.
 
-The primary purpose of C<BUILDARGS> is to allow a class to accept
-something other than named arguments. In the case of our C<Person>
-class, we are allowing it to be called with a single argument, a
-social security number:
+There are a couple pieces worth noting:
 
-  my $person = Person->new('123-45-6789');
+  use Moose;
+  extends qw( DateTime Moose::Object );
 
-The key part of our C<BUILDARGS> is this conditional:
+First, we C<use Moose> just like we always do. This lets us declare
+attributes and use all the Moose sugar to which we are accustomed.
 
-      if ( @_ == 1 && ! ref $_[0] ) {
-          return { ssn => $_[0] };
-      }
+The C<extends> declaration explicitly include L<Moose::Object> as well
+as L<DateTime>. This lets us use methods which are provided by
+L<Moose::Object>, like C<does>.
 
-By default, Moose constructors accept a list of key-value pairs, or a
-hash reference. We need to make sure that C<$_[0]> is not a reference
-before assuming it is a social security number.
+The constructor demonstrates a particular hack/pattern (hacktern?) for
+working with non-Moose parent classes:
 
-We call C<< $class->SUPER::BUILDARGS(@_) >> to handle all the other
-cases. You should always do this in your own C<BUILDARGS> methods,
-since L<Moose::Object> provides its own C<BUILDARGS> method that
-handles hash references and a list of key-value pairs.
+  sub new {
+      my $class = shift;
 
-The C<BUILD> method is called I<after> the object is constructed, but
-before it is returned to the caller. The C<BUILD> method provides an
-opportunity to check the object state as a whole. This is a good place
-to put logic that cannot be expressed as a type constraint on a single
-attribute.
+      my $obj = $class->SUPER::new(@_);
 
-In the C<Person> class, we need to check the relationship between two
-attributes, C<ssn> and C<country_of_residence>. We throw an exception
-if the object is not logically consistent.
+      return $class->meta->new_object(
+          __INSTANCE__ => $obj,
+          @_,
+      );
+  }
 
-=head1 MORE CONSIDERATIONS
+We explicitly call C<< $class->meta->new_object >> and pass the
+already-created object in the C<__INSTANCE__> key. Internally, Moose
+will take the existing object and initialize any attributes defined in
+our subclass.
 
-This recipe is made significantly simpler because all of the
-attributes are read-only. If the C<country_of_residence> attribute
-were settable, we would need to check that a Person had an C<ssn> if
-the new country was C<usa>. This could be done with a C<before>
-modifier.
+The C<after> modifier works just like we'd expect. The fact that
+C<set> is defined in our non-Moose parent does not matter.
 
 =head1 CONCLUSION
 
-We have repeatedly discouraged overriding C<new> in Moose
-classes. This recipe shows how you can use C<BUILDARGS> and C<BUILD>
-to hook into object construction without overriding C<new>
+Moose can play nice with non-Moose classes when you follow the pattern
+shown here. Your subclass has access to all the power of Moose,
+including attribute declaration, method modifiers, type constraints
+(for new attributes), and roles.
 
-The C<BUILDARGS> method lets us expand on Moose's built-in parameter
-handling for constructors. The C<BUILD> method lets us implement
-logical constraints across the whole object after it is created.
+However, you won't be able to easily override a parent's "attributes",
+since they're not Moose attributes. Nor will you be able to inline a
+constructor, since you need to explicitly use the metaclass's object
+constructor.
 
 =head1 AUTHOR
 
@@ -119,11 +118,24 @@ Dave Rolsky E<lt>autarch@urth.orgE<gt>
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright 2006-2009 by Infinity Interactive, Inc.
+Copyright 2009 by Infinity Interactive, Inc.
 
 L<http://www.iinteractive.com>
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
+=begin testing
+
+my $dt = My::DateTime->new( year => 1970, month => 2, day => 24 );
+
+can_ok( $dt, 'mayan_date' );
+isa_ok( $dt->mayan_date, 'DateTime::Calendar::Mayan' );
+is( $dt->mayan_date->date, '12.17.16.9.19', 'got expected mayan date' );
+
+$dt->set( year => 2009 );
+ok( ! $dt->has_mayan_date, 'mayan_date is cleared after call to ->set' );
+
+=end testing
+
 =cut
diff --git a/lib/Moose/Cookbook/Basics/Recipe12.pod b/lib/Moose/Cookbook/Basics/Recipe12.pod
deleted file mode 100644 (file)
index 1a44f67..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-=pod
-
-=begin testing-SETUP
-
-BEGIN {
-    eval 'use DateTime; use DateTime::Calendar::Mayan;';
-    if ($@) {
-        diag 'DateTime & DateTime::Calendar::Mayan required for this test';
-        ok(1);
-        exit 0;
-    }
-}
-
-=end testing-SETUP
-
-=head1 NAME
-
-Moose::Cookbook::Basics::Recipe12 - Extending a non-Moose base class
-
-=head1 SYNOPSIS
-
-  package My::DateTime;
-
-  use Moose;
-  extends qw( DateTime Moose::Object );
-
-  use DateTime::Calendar::Mayan;
-
-  has 'mayan_date' => (
-      is        => 'ro',
-      isa       => 'DateTime::Calendar::Mayan',
-      init_arg  => undef,
-      lazy      => 1,
-      builder   => '_build_mayan_date',
-      clearer   => '_clear_mayan_date',
-      predicate => 'has_mayan_date',
-  );
-
-  sub new {
-      my $class = shift;
-
-      my $obj = $class->SUPER::new(@_);
-
-      return $class->meta->new_object(
-          __INSTANCE__ => $obj,
-          @_,
-      );
-  }
-
-  after 'set' => sub {
-      $_[0]->_clear_mayan_date;
-  };
-
-  sub _build_mayan_date {
-      DateTime::Calendar::Mayan->from_object( object => $_[0] );
-  }
-
-=head1 DESCRIPTION
-
-This recipe demonstrates how to use Moose to subclass a parent which
-is not Moose based. This recipe only works if the parent class uses a
-blessed hash reference for object instances. If your parent is doing
-something funkier, you should check out L<MooseX::InsideOut>.
-
-You might also want to check out L<MooseX::NonMoose>, which does all
-the grunt work for you.
-
-There are a couple pieces worth noting:
-
-  use Moose;
-  extends qw( DateTime Moose::Object );
-
-First, we C<use Moose> just like we always do. This lets us declare
-attributes and use all the Moose sugar to which we are accustomed.
-
-The C<extends> declaration explicitly include L<Moose::Object> as well
-as L<DateTime>. This lets us use methods which are provided by
-L<Moose::Object>, like C<does>.
-
-The constructor demonstrates a particular hack/pattern (hacktern?) for
-working with non-Moose parent classes:
-
-  sub new {
-      my $class = shift;
-
-      my $obj = $class->SUPER::new(@_);
-
-      return $class->meta->new_object(
-          __INSTANCE__ => $obj,
-          @_,
-      );
-  }
-
-We explicitly call C<< $class->meta->new_object >> and pass the
-already-created object in the C<__INSTANCE__> key. Internally, Moose
-will take the existing object and initialize any attributes defined in
-our subclass.
-
-The C<after> modifier works just like we'd expect. The fact that
-C<set> is defined in our non-Moose parent does not matter.
-
-=head1 CONCLUSION
-
-Moose can play nice with non-Moose classes when you follow the pattern
-shown here. Your subclass has access to all the power of Moose,
-including attribute declaration, method modifiers, type constraints
-(for new attributes), and roles.
-
-However, you won't be able to easily override a parent's "attributes",
-since they're not Moose attributes. Nor will you be able to inline a
-constructor, since you need to explicitly use the metaclass's object
-constructor.
-
-=head1 AUTHOR
-
-Dave Rolsky E<lt>autarch@urth.orgE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright 2009 by Infinity Interactive, Inc.
-
-L<http://www.iinteractive.com>
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-=begin testing
-
-my $dt = My::DateTime->new( year => 1970, month => 2, day => 24 );
-
-can_ok( $dt, 'mayan_date' );
-isa_ok( $dt->mayan_date, 'DateTime::Calendar::Mayan' );
-is( $dt->mayan_date->date, '12.17.16.9.19', 'got expected mayan date' );
-
-$dt->set( year => 2009 );
-ok( ! $dt->has_mayan_date, 'mayan_date is cleared after call to ->set' );
-
-=end testing
-
-=cut
diff --git a/lib/Moose/Cookbook/Basics/Recipe8.pod b/lib/Moose/Cookbook/Basics/Recipe8.pod
new file mode 100644 (file)
index 0000000..fd82341
--- /dev/null
@@ -0,0 +1,125 @@
+
+=pod
+
+=head1 NAME
+
+Moose::Cookbook::Basics::Recipe9 - Builder methods and lazy_build
+
+=head1 SYNOPSIS
+
+  package BinaryTree;
+  use Moose;
+
+  has 'node' => (is => 'rw', isa => 'Any');
+
+  has 'parent' => (
+      is        => 'rw',
+      isa       => 'BinaryTree',
+      predicate => 'has_parent',
+      weak_ref  => 1,
+  );
+
+  has 'left' => (
+      is        => 'rw',
+      isa       => 'BinaryTree',
+      predicate => 'has_left',
+      lazy      => 1,
+      builder   => '_build_child_tree',
+  );
+
+  has 'right' => (
+      is        => 'rw',
+      isa       => 'BinaryTree',
+      predicate => 'has_right',
+      lazy      => 1,
+      builder   => '_build_child_tree',
+  );
+
+  before 'right', 'left' => sub {
+      my ($self, $tree) = @_;
+      $tree->parent($self) if defined $tree;
+  };
+
+  sub _build_child_tree {
+      my $self = shift;
+
+      return BinaryTree->new( parent => $self );
+  }
+
+=head1 DESCRIPTION
+
+If you've already read L<Moose::Cookbook::Basics::Recipe3>, then this
+example should look very familiar. In fact, all we've done here is
+replace the attribute's C<default> parameter with a C<builder>.
+
+In this particular case, the C<default> and C<builder> options act in
+exactly the same way. When the C<left> or C<right> attribute is read,
+Moose calls the builder method to initialize the attribute.
+
+Note that Moose calls the builder method I<on the object which has the
+attribute>. Here's an example:
+
+  my $tree = BinaryTree->new();
+
+  my $left = $tree->left();
+
+When C<< $tree->left() >> is called, Moose calls C<<
+$tree->_build_child_tree() >> in order to populate the C<left>
+attribute. If we had passed C<left> to the original constructor, the
+builder would not be called.
+
+There are some differences between C<default> and C<builder>. Notably,
+a builder is subclassable, and can be composed from a role. See
+L<Moose::Manual::Attributes> for more details.
+
+=head2 The lazy_build shortcut
+
+The C<lazy_build> attribute option can be used as sugar to specify
+a whole set of attribute options at once:
+
+  has 'animal' => (
+      is         => 'ro',
+      isa        => 'Animal',
+      lazy_build => 1,
+  );
+
+This is a shorthand for:
+
+  has 'animal' => (
+      is        => 'ro',
+      isa       => 'Animal',
+      required  => 1,
+      lazy      => 1,
+      builder   => '_build_animal',
+      predicate => 'has_animal',
+      clearer   => 'clear_animal',
+  );
+
+If your attribute starts with an underscore, Moose is smart and will
+do the right thing with the C<predicate> and C<clearer>, making them
+both start with an underscore. The C<builder> method I<always> starts
+with an underscore.
+
+You can read more about C<lazy_build> in L<Moose::Manual::Attributes>
+
+=head1 CONCLUSION
+
+The C<builder> option is a more OO-friendly version of the C<default>
+functionality. It also separates the default-generating code into a
+well-defined method. Sprinkling your attribute definitions with
+anonymous subroutines can be quite ugly and hard to follow.
+
+=head1 AUTHOR
+
+Dave Rolsky E<lt>autarch@urth.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2006-2009 by Infinity Interactive, Inc.
+
+L<http://www.iinteractive.com>
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
index fd82341..8cafe18 100644 (file)
 
 =head1 NAME
 
-Moose::Cookbook::Basics::Recipe9 - Builder methods and lazy_build
+Moose::Cookbook::Basics::Recipe10 - Operator overloading, subtypes, and coercion
 
 =head1 SYNOPSIS
 
-  package BinaryTree;
+  package Human;
+
   use Moose;
+  use Moose::Util::TypeConstraints;
 
-  has 'node' => (is => 'rw', isa => 'Any');
+  subtype 'Gender'
+      => as 'Str'
+      => where { $_ =~ m{^[mf]$}s };
 
-  has 'parent' => (
-      is        => 'rw',
-      isa       => 'BinaryTree',
-      predicate => 'has_parent',
-      weak_ref  => 1,
-  );
+  has 'gender' => ( is => 'ro', isa => 'Gender', required => 1 );
 
-  has 'left' => (
-      is        => 'rw',
-      isa       => 'BinaryTree',
-      predicate => 'has_left',
-      lazy      => 1,
-      builder   => '_build_child_tree',
-  );
+  has 'mother' => ( is => 'ro', isa => 'Human' );
+  has 'father' => ( is => 'ro', isa => 'Human' );
 
-  has 'right' => (
-      is        => 'rw',
-      isa       => 'BinaryTree',
-      predicate => 'has_right',
-      lazy      => 1,
-      builder   => '_build_child_tree',
-  );
+  use overload '+' => \&_overload_add, fallback => 1;
+
+  sub _overload_add {
+      my ( $one, $two ) = @_;
 
-  before 'right', 'left' => sub {
-      my ($self, $tree) = @_;
-      $tree->parent($self) if defined $tree;
-  };
+      die('Only male and female humans may create children')
+          if ( $one->gender() eq $two->gender() );
 
-  sub _build_child_tree {
-      my $self = shift;
+      my ( $mother, $father )
+          = ( $one->gender eq 'f' ? ( $one, $two ) : ( $two, $one ) );
 
-      return BinaryTree->new( parent => $self );
+      my $gender = 'f';
+      $gender = 'm' if ( rand() >= 0.5 );
+
+      return Human->new(
+          gender => $gender,
+          mother => $mother,
+          father => $father,
+      );
   }
 
 =head1 DESCRIPTION
 
-If you've already read L<Moose::Cookbook::Basics::Recipe3>, then this
-example should look very familiar. In fact, all we've done here is
-replace the attribute's C<default> parameter with a C<builder>.
+This Moose cookbook recipe shows how operator overloading, coercion,
+and sub types can be used to mimic the human reproductive system
+(well, the selection of genes at least).
 
-In this particular case, the C<default> and C<builder> options act in
-exactly the same way. When the C<left> or C<right> attribute is read,
-Moose calls the builder method to initialize the attribute.
+=head1 INTRODUCTION
 
-Note that Moose calls the builder method I<on the object which has the
-attribute>. Here's an example:
+Our C<Human> class uses operator overloading to allow us to "add" two
+humans together and produce a child. Our implementation does require
+that the two objects be of opposite genders. Remember, we're talking
+about biological reproduction, not marriage.
 
-  my $tree = BinaryTree->new();
+While this example works as-is, we can take it a lot further by adding
+genes into the mix. We'll add the two genes that control eye color,
+and use overloading to combine the genes from the parent to model the
+biology.
 
-  my $left = $tree->left();
+=head2 What is Operator Overloading?
 
-When C<< $tree->left() >> is called, Moose calls C<<
-$tree->_build_child_tree() >> in order to populate the C<left>
-attribute. If we had passed C<left> to the original constructor, the
-builder would not be called.
+Overloading is I<not> a Moose-specific feature. It's a general OO
+concept that is implemented in Perl with the C<overload>
+pragma. Overloading lets objects do something sane when used with
+Perl's built in operators, like addition (C<+>) or when used as a
+string.
 
-There are some differences between C<default> and C<builder>. Notably,
-a builder is subclassable, and can be composed from a role. See
-L<Moose::Manual::Attributes> for more details.
+In this example we overload addition so we can write code like
+C<$child = $mother + $father>.
 
-=head2 The lazy_build shortcut
+=head1 GENES
 
-The C<lazy_build> attribute option can be used as sugar to specify
-a whole set of attribute options at once:
+There are many genes which affect eye color, but there are two which
+are most important, I<gey> and I<bey2>. We will start by making a
+class for each gene.
 
-  has 'animal' => (
-      is         => 'ro',
-      isa        => 'Animal',
-      lazy_build => 1,
-  );
+=head2 Human::Gene::bey2
+
+  package Human::Gene::bey2;
+
+  use Moose;
+  use Moose::Util::TypeConstraints;
+
+  type 'bey2_color' => where { $_ =~ m{^(?:brown|blue)$} };
+
+  has 'color' => ( is => 'ro', isa => 'bey2_color' );
+
+This class is trivial, We have a type constraint for the allowed
+colors, and a C<color> attribute.
+
+=head2 Human::Gene::gey
+
+  package Human::Gene::gey;
+
+  use Moose;
+  use Moose::Util::TypeConstraints;
+
+  type 'gey_color' => where { $_ =~ m{^(?:green|blue)$} };
+
+  has 'color' => ( is => 'ro', isa => 'gey_color' );
+
+This is nearly identical to the C<Humane::Gene::bey2> class, except
+that the I<gey> gene allows for different colors.
+
+=head1 EYE COLOR
+
+We could just give add four attributes (two of each gene) to the
+C<Human> class, but this is a bit messy. Instead, we'll abstract the
+genes into a container class, C<Human::EyeColor>. Then a C<Human> can
+have a single C<eye_color> attribute.
+
+  package Human::EyeColor;
+
+  use Moose;
+  use Moose::Util::TypeConstraints;
+
+  coerce 'Human::Gene::bey2'
+      => from 'Str'
+          => via { Human::Gene::bey2->new( color => $_ ) };
+
+  coerce 'Human::Gene::gey'
+      => from 'Str'
+          => via { Human::Gene::gey->new( color => $_ ) };
+
+  has [qw( bey2_1 bey2_2 )] =>
+      ( is => 'ro', isa => 'Human::Gene::bey2', coerce => 1 );
+
+  has [qw( gey_1 gey_2 )] =>
+      ( is => 'ro', isa => 'Human::Gene::gey', coerce => 1 );
+
+The eye color class has two of each type of gene. We've also created a
+coercion for each class that coerces a string into a new object. Note
+that a coercion will fail if it attempts to coerce a string like
+"indigo", because that is not a valid color for either type of gene.
+
+As an aside, you can see that we can define several identical
+attributes at once by supply an array reference of names as the first
+argument to C<has>.
+
+We also need a method to calculate the actual eye color that results
+from a set of genes. The I<bey2> brown gene is dominant over both blue
+and green. The I<gey> green gene dominant over blue.
+
+  sub color {
+      my ($self) = @_;
+
+      return 'brown'
+          if ( $self->bey2_1->color() eq 'brown'
+          or $self->bey2_2->color() eq 'brown' );
 
-This is a shorthand for:
+      return 'green'
+          if ( $self->gey_1->color() eq 'green'
+          or $self->gey_2->color() eq 'green' );
 
-  has 'animal' => (
-      is        => 'ro',
-      isa       => 'Animal',
-      required  => 1,
-      lazy      => 1,
-      builder   => '_build_animal',
-      predicate => 'has_animal',
-      clearer   => 'clear_animal',
+      return 'blue';
+  }
+
+We'd like to be able to treat a C<Human::EyeColor> object as a string,
+so we define a string overloading for the class:
+
+  use overload '""' => \&color, fallback => 1;
+
+Finally, we need to define overloading for addition. That way we can
+add together to C<Human::EyeColor> objects and get a new one with a
+new (genetically correct) eye color.
+
+  use overload '+' => \&_overload_add, fallback => 1;
+
+  sub _overload_add {
+      my ( $one, $two ) = @_;
+
+      my $one_bey2 = 'bey2_' . _rand2();
+      my $two_bey2 = 'bey2_' . _rand2();
+
+      my $one_gey = 'gey_' . _rand2();
+      my $two_gey = 'gey_' . _rand2();
+
+      return Human::EyeColor->new(
+          bey2_1 => $one->$one_bey2->color(),
+          bey2_2 => $two->$two_bey2->color(),
+          gey_1  => $one->$one_gey->color(),
+          gey_2  => $two->$two_gey->color(),
+      );
+  }
+
+  sub _rand2 {
+      return 1 + int( rand(2) );
+  }
+
+When two eye color objects are added together the C<_overload_add()>
+method will be passed two C<Human::EyeColor> objects. These are the
+left and right side operands for the C<+> operator. This method
+returns a new C<Human::EyeColor> object.
+
+=head1 ADDING EYE COLOR TO C<Human>s
+
+Our original C<Human> class requires just a few changes to incorporate
+our new C<Human::EyeColor> class.
+
+  use List::MoreUtils qw( zip );
+
+  coerce 'Human::EyeColor'
+      => from 'ArrayRef'
+      => via { my @genes = qw( bey2_1 bey2_2 gey_1 gey_2 );
+               return Human::EyeColor->new( zip( @genes, @{$_} ) ); };
+
+  has 'eye_color' => (
+      is       => 'ro',
+      isa      => 'Human::EyeColor',
+      coerce   => 1,
+      required => 1,
   );
 
-If your attribute starts with an underscore, Moose is smart and will
-do the right thing with the C<predicate> and C<clearer>, making them
-both start with an underscore. The C<builder> method I<always> starts
-with an underscore.
+We also need to modify C<_overload_add()> in the C<Human> class to
+account for eye color:
 
-You can read more about C<lazy_build> in L<Moose::Manual::Attributes>
+  return Human->new(
+      gender    => $gender,
+      eye_color => ( $one->eye_color() + $two->eye_color() ),
+      mother    => $mother,
+      father    => $father,
+  );
 
 =head1 CONCLUSION
 
-The C<builder> option is a more OO-friendly version of the C<default>
-functionality. It also separates the default-generating code into a
-well-defined method. Sprinkling your attribute definitions with
-anonymous subroutines can be quite ugly and hard to follow.
+The three techniques we used, overloading, subtypes, and coercion,
+combine to provide a powerful interface.
 
-=head1 AUTHOR
+If you'd like to learn more about overloading, please read the
+documentation for the L<overload> pragma.
 
-Dave Rolsky E<lt>autarch@urth.orgE<gt>
+To see all the code we created together, take a look at
+F<t/000_recipes/basics/010_genes.t>.
+
+=head1 NEXT STEPS
+
+Has this been a real project we'd probably want to:
+
+=over 4
+
+=item Better Randomization with Crypt::Random
+
+=item Characteristic Base Class
 
-=head1 COPYRIGHT AND LICENSE
+=item Mutating Genes
 
-Copyright 2006-2009 by Infinity Interactive, Inc.
+=item More Characteristics
 
-L<http://www.iinteractive.com>
+=item Artificial Life
 
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
+=back
+
+=head1 AUTHORS
+
+Aran Clary Deltac <bluefeet@cpan.org>
+
+Dave Rolsky E<lt>autarch@urth.orgE<gt>
+
+=head1 LICENSE
+
+This work is licensed under a Creative Commons Attribution 3.0 Unported License.
+
+License details are at: L<http://creativecommons.org/licenses/by/3.0/>
 
 =cut
+