Wrote recipe9, builder and lazy_build.
Dave Rolsky [Fri, 2 May 2008 00:45:39 +0000 (00:45 +0000)]
Added recipe9 (and 7) to changes for 0.44

Changes
MANIFEST
lib/Moose/Cookbook.pod
lib/Moose/Cookbook/Recipe3.pod
lib/Moose/Cookbook/Recipe9.pod [new file with mode: 0644]

diff --git a/Changes b/Changes
index aa9bde1..ef49b07 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,11 @@
 Revision history for Perl extension Moose
 
+0.44
+    * Moose::Cookbook::Recipe7
+      - added new recipe for immutable functionality (Dave Rolsky)
+    * Moose::Cookbook::Recipe9
+      - added new recipe for builder and lazy-builder (Dave Rolsky)
+
 0.43 Wed. April, 30, 2008
     * NOTE TO SELF:
         drink more coffee before 
index beedbb0..d225c5d 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -22,6 +22,7 @@ lib/Moose/Cookbook/Recipe4.pod
 lib/Moose/Cookbook/Recipe5.pod
 lib/Moose/Cookbook/Recipe6.pod
 lib/Moose/Cookbook/Recipe7.pod
+lib/Moose/Cookbook/Recipe9.pod
 lib/Moose/Cookbook/Snack/Types.pod
 lib/Moose/Cookbook/WTF.pod
 lib/Moose/Meta/Attribute.pm
index 9261653..59e192e 100644 (file)
@@ -61,9 +61,11 @@ 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::Recipe9> - ?? 
+=item L<Moose::Cookbook::Recipe9> - Builder methods and lazy_build
 
-I<abstract goes here>
+Lazy attributes do not get set via their defaults until they are
+accessed. The builder feature provides an inheritable and
+role-composable way to provide a default attribute value.
 
 =back
 
index da06f7b..16836bb 100644 (file)
@@ -219,6 +219,9 @@ In short, don't use them unless you know what you are doing :)
 You I<can> use the C<default> option without the C<lazy> option if 
 you like, as we showed in the second recipe.
 
+And actually, you can use C<builder> instead of C<default>. See
+L<Moose::Cookbook::Recipe9> for details.
+
 =back
 
 =head1 AUTHOR
diff --git a/lib/Moose/Cookbook/Recipe9.pod b/lib/Moose/Cookbook/Recipe9.pod
new file mode 100644 (file)
index 0000000..d028087
--- /dev/null
@@ -0,0 +1,193 @@
+
+=pod
+
+=head1 NAME
+
+Moose::Cookbook::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::Recipe3>, then this example
+should look awfully familiar. In fact, all we've done here is replace
+the attribute C<default> with a C<builder> method.
+
+In this particular case, the C<default> and C<builder> act exactly the
+same. When the C<left> or C<right> attribute is first accessed before
+it has been set, Moose will call the specified C<builder> method to
+populate the attribute.
+
+=head2 Subclassable
+
+There are some differences between C<default> and C<builder>. Because
+C<builder> is called I<by name>, it goes through Perl's normal
+inheritance system. This means that builder methods are both
+inheritable and overrideable.
+
+For example, we might make a C<BinaryTree> subclass:
+
+  package TrinaryTree;
+  use Moose;
+
+  extends 'BinaryTree';
+
+  has 'middle' => (
+      is        => 'rw',
+      isa       => 'BinaryTree',
+      predicate => 'has_middle',
+      lazy      => 1,
+      builder   => '_build_child_tree',
+  );
+
+This doesn't quite work though. If you look closely at the
+C<_build_child_tree> method defined in C<BinaryTree>, you'll notice
+that it hard-codes a class name. Naughty us!
+
+Also, as a bonus, we'll pass C<@_> through, so subclasses can override
+the method to pass additional options to the constructor.
+
+Good object-oriented code should allow itself to be subclassed
+gracefully. Let's tweak C<_build_child_tree>:
+
+  sub _build_child_tree
+      my $self = shift;
+
+      return (ref $self)->new( parent => $self, @_ );
+  }
+
+Now C<_build_child_tree> can be gracefully inherited and overridden.
+
+=head2 Composable
+
+There's more to builders than just subclassing, though. The fact that
+builders are called by name also makes them suitable for use in a
+role.
+
+  package HasAnimal;
+  use Moose::Role;
+
+  requires '_build_animal';
+
+  has 'animal' => (
+      is      => 'ro',
+      isa     => 'Animal',
+      lazy    => 1,
+      builder => '_build_animal',
+  );
+
+This role provides an animal attribute, but requires that the consumer
+of the role provide a builder method it.
+
+  package CatLover;
+  use Moose;
+
+  with 'HasAnimal';
+
+  sub _build_animal {
+      return Cat->new();
+  }
+
+This simply could not be done using a C<default>.
+
+=head2 The lazy_build shortcut
+
+The C<lazy_build> attribute parameter can be used as sugar to specify
+a whole bunch of options at once.
+
+  has 'animal' => (
+      is         => 'ro',
+      isa        => 'Animal',
+      lazy_build => 1,
+  );
+
+This is a shorthand for this:
+
+  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, since you will want this to be private the vast
+majority of the time.
+
+=head1 CONCLUSION
+
+The C<builder> option is a more OO-friendly version of the C<default>
+functionality. It also has the property of separating out the code
+into a separate well-defined method. This alone makes it valuable. It
+is quite ugly to jam a long default code reference into your attribute
+definition.
+
+Here are some good rules for determining when to use C<builder> vs
+C<default>.
+
+If the default value is a simple scalar that only needs to be
+calculated once (or a constant), use C<default>.
+
+If the default value is an empty reference that needs to be wrapped in
+a coderef like C<sub { [] }>, use C<default>.
+
+Otherwise, use C<builder>.
+
+=head1 AUTHOR
+
+Dave Rolsky E<lt>autarch@urth.orgE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2006-2008 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