1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
=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> 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.
Note that Moose calls the builder method I<on the object which has the
attribute>. Here's an example in code:
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 builer would not be called.
=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();
}
=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.
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>.
=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>.
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@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
|