overriding new isn't necessary when using mx-nonmoose
[gitmo/Moose.git] / lib / Moose / Cookbook / Basics / Recipe11.pod
index 4c36c80..e64902e 100644 (file)
+package Moose::Cookbook::Basics::Recipe11;
 
-=pod
+# ABSTRACT: Extending a non-Moose base class
 
-=head1 NAME
+__END__
 
-Moose::Cookbook::Basics::Recipe11 - Using BUILDARGS and BUILD to hook into object construction
 
-=head1 SYNOPSIS
+=pod
 
-  package Person;
+=begin testing-SETUP
 
-  has 'ssn' => (
-      is        => 'ro',
-      isa       => 'Str',
-      predicate => 'has_ssn',
-  );
+use Test::Requires {
+    'DateTime'                  => '0',
+    'DateTime::Calendar::Mayan' => '0',
+    'MooseX::NonMoose'          => '0',
+};
 
-  has 'country_of_residence' => (
-      is      => 'ro',
-      isa     => 'Str',
-      default => 'usa'
-  );
+=end testing-SETUP
 
-  has 'first_name' => (
-      is  => 'ro',
-      isa => 'Str',
-  );
+=head1 SYNOPSIS
 
-  has 'last_name' => (
-      is  => 'ro',
-      isa => 'Str',
-  );
+  package My::DateTime;
 
-  sub BUILDARGS {
-      my $class = shift;
+  use Moose;
+  use MooseX::NonMoose;
+  extends qw( DateTime );
 
-      if ( @_ == 1 && ! ref $_[0] ) {
-          return { ssn => $_[0] };
-      }
-      else {
-          return $class->SUPER::BUILDARGS(@_);
-      }
-  }
+  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 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>.
-
-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.
-
-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 $person = Person->new('123-45-6789');
-
-The key part of our C<BUILDARGS> is this conditional:
-
-      if ( @_ == 1 && ! ref $_[0] ) {
-          return { ssn => $_[0] };
-      }
-
-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.
-
-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.
-
-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
-object.
-
-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.
-
-=head1 MORE CONSIDERATIONS
-
-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
-
-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>
-
-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.
+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::NonMoose::InsideOut> and L<MooseX::InsideOut>.
 
-=head1 AUTHOR
+The meat of this recipe is contained in L<MooseX::NonMoose>, which does all
+the grunt work for you.
 
-Dave Rolsky E<lt>autarch@urth.orgE<gt>
+=begin testing
 
-=head1 COPYRIGHT AND LICENSE
+my $dt = My::DateTime->new( year => 1970, month => 2, day => 24 );
 
-Copyright 2006-2009 by Infinity Interactive, Inc.
+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' );
 
-L<http://www.iinteractive.com>
+$dt->set( year => 2009 );
+ok( ! $dt->has_mayan_date, 'mayan_date is cleared after call to ->set' );
 
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
+=end testing
 
 =cut