recipe-1
Stevan Little [Sat, 25 Mar 2006 19:27:34 +0000 (19:27 +0000)]
lib/Moose/Cookbook/Recipe1.pod
lib/Moose/Cookbook/Recipe2.pod

index 2c84868..b672444 100644 (file)
@@ -3,7 +3,7 @@
 
 =head1 NAME
 
-Moose::Cookbook::Recipe1
+Moose::Cookbook::Recipe1 - The (always classic) cartesian point example.
 
 =head1 SYNOPSIS
 
@@ -37,6 +37,188 @@ Moose::Cookbook::Recipe1
 
 =head1 DESCRIPTION
 
+This is the classic Point example. This one in particular I took 
+from the Perl 6 Apocalypse 12 document, but it is similar to the 
+example found in the classic K&R C book as well, and many other 
+places. And now, onto the code:
+
+As with all Perl 5 classes, a Moose class is defined in a package. 
+Of course we always use C<strict> and C<warnings> (don't forget 
+that a kitten will die if you don't) and then we C<use Moose>.
+
+By loading Moose, we are enabeling the Moose "environment" to be 
+loaded within our package. This means that we export some functions 
+which serve as Moose "keywords". This is nothing fancier than that, 
+just plain old exported functions.
+
+Another important thing happens at this stage as well. Moose will 
+automatically set your package's superclass to be L<Moose::Object>.
+The reason we do this, is so that we can be sure that you will 
+inherit from L<Moose::Object> and get the benefits that provides 
+(see the L<Moose::Object> for those details). However, you don't 
+actually I<have> to inherit from L<Moose::Object> if you don't  
+want to, all other features of Moose are still accessible to you.
+
+Now, onto the keywords. The first one we see here is C<has>, which 
+defines an instance attribute in your class. 
+
+  has 'x' => (isa => 'Int', is => 'ro');
+
+This will create an attribute named C<x>, it will expect that the 
+value stored in the attribute to pass the type constraint C<Int> (1), 
+and the accessor generated for this attribute will be read-only 
+(abbreviated as C<ro>).
+
+The next C<has> line is very similar, with only one difference.
+
+  has 'y' => (isa => 'Int', is => 'rw');
+
+For the C<y> attribute a read/write accessor will be generated 
+(abbreviated as C<rw>). 
+
+At this point the attributes have been defined, and it is time to 
+define our methods. In Moose, as with regular Perl 5 OO, a method 
+is just a subroutine defined within the package. So here we create 
+the C<clear> method.
+
+  sub clear {
+      my $self = shift;
+      $self->{x} = 0;
+      $self->y(0);    
+  }
+
+It is pretty standard, the only thing to note is that we are directly 
+accessing the C<x> slot in the instance L<(2)>. This is because the 
+value was created with a read-only accessor. This also shows that Moose 
+objects are not anything out of the ordinary, but just regular old 
+blessed HASH references. This means they are very compatible with 
+other Perl 5 (non-Moose) classes as well. 
+
+The next part of the code to review is the B<Point> subclass, 
+B<Point3D>. The first item you might notice is that we do not use 
+the standard C<use base> declaration here. Instead we use the Moose 
+keyword C<extends> like so:
+
+  extends 'Point';
+
+This keyword will function very much like C<use base> does in that 
+it will make an attempt to load your class if it has not already been 
+loaded. However, it differs on one important point. The C<extends> 
+keyword will overwrite any previous values in your package's C<@ISA>, 
+where C<use base> will C<push> values onto the package's C<@ISA>. It 
+is my opinion that the behavior of C<extends> is more intuitive in 
+that it is more explicit about defining the superclass relationship.
+
+A small digression here, both Moose and C<extends> support multiple 
+inheritence. You simply pass all the superclasses to C<extends>, 
+like so:
+
+  extends 'Foo', 'Bar', 'Baz';
+  
+Now, back to our B<Point3D> class. The next thing we do is to create 
+a new attribute for B<Point3D> called C<z>.
+
+  has 'z' => (isa => 'Int');
+
+As with B<Point>'s C<x> and C<y> attributes, this attribute has a 
+type constraint of C<Int>, but it differs in that it does B<not> 
+ask for any autogenerated accessors. The result being (aside from 
+breaking object encapsulation), that C<x> is a private attribute.
+
+Next comes another Moose feature which we call method "modifiers" 
+(or method "advice" for the AOP inclined). The modifier used here 
+is the C<after> modifier, and looks like this:
+
+  after 'clear' => sub {
+      my $self = shift;
+      $self->{z} = 0;
+  };
+
+This modifier tells Moose to install a C<clear> method for 
+B<Point3D> that will first run the C<clear> method for the 
+superclass (in this case C<Point::clear>), and then run this 
+method I<after> it (passing in the same arguments as the original 
+method). 
+
+Now, of course using the C<after> modifier is not the only way to 
+accomplish this. I mean, after all, this B<is> Perl right? You 
+would get the same results with this code:
+
+  sub clear {
+      my $self = shift;
+      $self->SUPER::clear();
+      $self->{z} = 0;
+  }
+
+You could also use another Moose method modifier, C<override> here, 
+and get the same results again. Here is how that would look.
+
+  override 'clear' => sub {
+      my $self = shift;
+      super();
+      $self->{z} = 0;
+  };
+  
+The C<override> modifier allows you to use the C<super> keyword 
+within it to dispatch to the superclass's method in a very Ruby-ish 
+style.
+
+Now of course, what use is a class if you cant instantiate objects 
+with it. Now since B<Point> inherits from L<Moose::Object>, it will 
+inherit the default L<Moose::Object> constructor called C<new>. Here 
+are two examples of how that is used:
+
+  my $point = Point->new(x => 1, y => 2);   
+  my $point3d = Point3D->new(x => 1, y => 2, z => 3);
+
+As you can see, C<new> accepts named argument pairs for any of the 
+attributes. It does not I<require> that you pass in the all the 
+attributes, and it will politely ignore any named arguments it does 
+not recognize. 
+
+From here, you can use C<$point> and C<$point3d> just as you would 
+any other Perl 5 object. 
+
+=head1 CONCLUSION
+
+I hope this recipe has given you some explaination of how to use 
+Moose to build you Perl 5 classes. The next recipe will build upon 
+the basics shown here with more complex attributes and methods. 
+Please read on :)
+
+=head1 FOOTNOTES
+
+=over 4
+
+=item (1)
+
+Several default type constraints are provided by Moose, of which 
+C<Int> is one. For more information on the built-in type constraints 
+and the type constraint system in general, see the 
+L<Moose::Util::TypeConstraints> documentation.
+
+=item (2)
+
+Future plans for Moose include allowing for alternate instance 
+structures such as blessed ARRAY refs and such. If you want you Moose 
+classes to be interchangable, it is advised that you avoid direct 
+instance access, like that which is shown above.
+
+=back
+
+=head1 SEE ALSO
+
+=over 4
+
+=item Method Modifiers
+
+The concept of method modifiers is directly ripped off from CLOS. A 
+great explaination of them can be found by following this link.
+
+L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html>
+
+=back
+
 =head1 AUTHOR
 
 Stevan Little E<lt>stevan@iinteractive.comE<gt>
index ce8ca3b..1786c1b 100644 (file)
@@ -37,12 +37,12 @@ Moose::Cookbook::Recipe2
   has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');       
   
   before 'withdraw' => sub {
-       my ($self, $amount) = @_;
-       my $overdraft_amount = $amount - $self->balance();
-       if ($overdraft_amount > 0) {
-               $self->overdraft_account->withdraw($overdraft_amount);
-               $self->deposit($overdraft_amount);
-       }
+      my ($self, $amount) = @_;
+      my $overdraft_amount = $amount - $self->balance();
+      if ($overdraft_amount > 0) {
+          $self->overdraft_account->withdraw($overdraft_amount);
+          $self->deposit($overdraft_amount);
+      }
   };
 
 =head1 DESCRIPTION