[Moose-commits] r7606 - in Moose/trunk/lib/Moose: Cookbook/Basics Manual

autarch at code2.0beta.co.uk autarch at code2.0beta.co.uk
Tue Feb 10 15:47:39 GMT 2009


Author: autarch
Date: 2009-02-10 07:47:39 -0800 (Tue, 10 Feb 2009)
New Revision: 7606

Modified:
   Moose/trunk/lib/Moose/Cookbook/Basics/Recipe9.pod
   Moose/trunk/lib/Moose/Manual/Attributes.pod
Log:
Revised basics recipe 9 and moved a lot of its content over to Moose::Manual::Attributes

Modified: Moose/trunk/lib/Moose/Cookbook/Basics/Recipe9.pod
===================================================================
--- Moose/trunk/lib/Moose/Cookbook/Basics/Recipe9.pod	2009-02-10 15:37:08 UTC (rev 7605)
+++ Moose/trunk/lib/Moose/Cookbook/Basics/Recipe9.pod	2009-02-10 15:47:39 UTC (rev 7606)
@@ -48,100 +48,34 @@
 
 =head1 DESCRIPTION
 
-If you've already read L<Moose::Cookbook::Basics::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.
+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 get
-method is called, Moose will call the builder method to initialize the
-attribute.
+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 in code:
+attribute>. Here's an example:
 
   my $tree = BinaryTree->new();
 
   my $left = $tree->left();
 
-At this point, Moose will call 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.
+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.
 
-=head2 Subclassable
+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.
 
-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 overridable.
-
-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();
-  }
-
 =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.
+a whole set of attribute parameters at once:
 
   has 'animal' => (
       is         => 'ro',
@@ -149,7 +83,7 @@
       lazy_build => 1,
   );
 
-This is a shorthand for this:
+This is a shorthand for:
 
   has 'animal' => (
       is        => 'ro',
@@ -164,36 +98,17 @@
 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.
+with an underscore.
 
-Note that the C<builder> method name is created by simply taking
-"_build_" and appending the attribute name. This means that attributes
-with a leading underscore like C<_animal> end up with a builder named
-C<_build__animal>.
+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 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.
+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.
 
-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>.
-
-This ensures that your classes are easily subclassable, and also helps
-keep crufty code out of your attribute definition blocks.
-
 =head1 AUTHOR
 
 Dave Rolsky E<lt>autarch at urth.orgE<gt>

Modified: Moose/trunk/lib/Moose/Manual/Attributes.pod
===================================================================
--- Moose/trunk/lib/Moose/Manual/Attributes.pod	2009-02-10 15:37:08 UTC (rev 7605)
+++ Moose/trunk/lib/Moose/Manual/Attributes.pod	2009-02-10 15:47:39 UTC (rev 7606)
@@ -250,12 +250,52 @@
 
 This has several advantages. First, it moves a chunk of code to its
 own named method, which improves readability and code
-organization. Second, the C<_build_size> method can be overridden in
-subclasses.
+organization.
 
 We strongly recommend that you use a C<builder> instead of a
 C<default> for anything beyond the most trivial default.
 
+=head3 Builders allow subclassing
+
+Because the C<builder> is called I<by name>, it goes through Perl's
+method resolution. This means that builder methods are both
+inheritable and overridable.
+
+If we subclass our C<Person> class, we can override C<_build_size>:
+
+  package Lilliputian;
+
+  use Moose;
+  extends 'Person';
+
+  sub _build_size { return 'small' }
+
+=head3 Builders can be composed from roles
+
+Because builders are called by name, they work well with roles. For
+example, a role could provide an attribute but require that the
+consuming class provide the C<builder>:
+
+  package HasSize;
+  use Moose::Role;
+
+  requires '_build_size';
+
+  has 'size' => (
+      is      => 'ro',
+      lazy    => 1,
+      builder => '_build_animal',
+  );
+
+  package Lilliputian;
+  use Moose;
+
+  with 'HasSize';
+
+  sub _build_size { return 'small' }
+
+Roles are covered in L<Moose::Manual::Roles>.
+
 =head2 Laziness and C<lazy_build>
 
 Moose lets you defer attribute population by making an attribute




More information about the Moose-commits mailing list