=head2 Read-write vs. read-only
-The options passed to C<has> define the properties of the
-attribute. There are many options, but in the simplest form you just
-need to set C<is>, which can be either C<rw> (read-write) or C<ro>
-(read-only). When an attribute is C<rw>, you can change it by passing
-a value to its accessor. When an attribute is C<ro>, you may only read
-the current value of the attribute.
+The options passed to C<has> define the properties of the attribute. There are
+many options, but in the simplest form you just need to set C<is>, which can
+be either C<ro> (read-only) or C<rw> (read-write). When an attribute is C<rw>,
+you can change it by passing a value to its accessor. When an attribute is
+C<ro>, you may only read the current value of the attribute.
In fact, you could even omit C<is>, but that gives you an attribute
that has no accessor. This can be useful with other attribute options,
predicate => 'has_size',
);
-This is dumb example, but it illustrates the point that the subroutine
+This is a trivial example, but it illustrates the point that the subroutine
will be called for every new object created.
When you provide a C<default> subroutine reference, it is called as a
method on the object, with no additional parameters:
has 'size' => (
- is => 'ro',
+ is => 'ro',
default => sub {
my $self = shift;
- return $self->height > 200 ? 'big' : 'average';
+ return $self->height > 200 ? 'large' : 'average';
},
);
attribute C<lazy>. Laziness is covered in the next section.
If you want to use a reference of any sort as the default value, you
-must return it from a subroutine. This is necessary because otherwise
-Perl would instantiate the reference exactly once, and it would be
-shared by all objects:
+must return it from a subroutine.
+
+ has 'mapping' => (
+ is => 'ro',
+ default => sub { {} },
+ );
+
+This is necessary because otherwise Perl would instantiate the reference
+exactly once, and it would be shared by all objects:
has 'mapping' => (
is => 'ro',
If Moose allowed this then the default mapping attribute could easily
end up shared across many objects. Instead, wrap it in a subroutine
-reference:
-
- has 'mapping' => (
- is => 'ro',
- default => sub { {} }, # right!
- );
+reference as we saw above.
This is a bit awkward, but it's just the way Perl works.
-As an alternative to using a subroutine reference, you can instead
-supply a C<builder> method for your attribute:
+As an alternative to using a subroutine reference, you can supply a C<builder>
+method for your attribute:
has 'size' => (
is => 'ro',
return ( 'small', 'medium', 'large' )[ int( rand 3 ) ];
}
-This has several advantages. First, it moves a chunk of code to its
-own named method, which improves readability and code
-organization.
+This has several advantages. First, it moves a chunk of code to its own named
+method, which improves readability and code organization. Second, because this
+is a I<named> method, it can be subclassed or provided by a role.
We strongly recommend that you use a C<builder> instead of a
C<default> for anything beyond the most trivial default.
sub _build_size { return 'small' }
-=head3 Builders can be composed from roles
+=head3 Builders work well with roles
Because builders are called by name, they work well with roles. For
example, a role could provide an attribute but require that the
Roles are covered in L<Moose::Manual::Roles>.
-=head2 Laziness and C<lazy_build>
+=head2 Laziness
Moose lets you defer attribute population by making an attribute
C<lazy>:
We recommend that you make any attribute with a builder or non-trivial
default C<lazy> as a matter of course.
-To facilitate this, you can simply specify the C<lazy_build> attribute
-option. This bundles up a number of options together:
-
- has 'size' => (
- is => 'ro',
- lazy_build => 1,
- );
-
-This is the same as specifying all of these options:
-
- has 'size' => (
- is => 'ro',
- lazy => 1,
- builder => '_build_size',
- clearer => 'clear_size',
- predicate => 'has_size',
- );
-
-If your attribute name starts with an underscore (C<_>), then the clearer
-and predicate will as well:
-
- has '_size' => (
- is => 'ro',
- lazy_build => 1,
- );
-
-becomes:
-
- has '_size' => (
- is => 'ro',
- lazy => 1,
- builder => '_build__size',
- clearer => '_clear_size',
- predicate => '_has_size',
- );
-
-Note the doubled underscore in the builder name. Internally, Moose
-simply prepends the attribute name with "_build_" to come up with the
-builder name.
-
-If you don't like the names that C<lazy_build> generates, you can
-always provide your own:
-
- has 'size' => (
- is => 'ro',
- lazy_build => 1,
- clearer => '_clear_size',
- );
-
-Options that you explicitly provide are always used in favor of
-Moose's internal defaults.
-
=head2 Constructor parameters (C<init_arg>)
By default, each attribute can be passed by name to the class's
the constructor parameter. You may also want to make an attribute
unsettable via the constructor.
-Both of these goals can be accomplished with the C<init_arg> option:
+You can do either of these things with the C<init_arg> option:
has 'bigness' => (
is => 'ro',
the constructor. This is particularly handy for private attributes:
has '_genetic_code' => (
- is => 'ro',
- lazy_build => 1,
- init_arg => undef,
+ is => 'ro',
+ lazy => 1,
+ builder => '_build_genetic_code',
+ init_arg => undef,
);
By setting the C<init_arg> to C<undef>, we make it impossible to set
);
sub _size_set {
- my ( $self, $size ) = @_;
+ my ( $self, $size, $old_size ) = @_;
- warn $self->name, " size is now $size\n";
+ my $msg = $self->name;
+
+ if ( @_ > 2 ) {
+ $msg .= " - old size was $old_size";
+ }
+
+ $msg .= " - size is now $size";
+ warn $msg;
}
-The trigger is called as a method, and receives the new value as its argument.
-The trigger is called I<after> the value is set.
+The trigger is called I<after> an attribute's value is set. It is
+called as a method on the object, and receives the new and old values as
+its arguments. If the attribute had not previously been set at all,
+then only the new value is passed. This lets you distinguish between
+the case where the attribute had no value versus when the old value was C<undef>.
This differs from an C<after> method modifier in two ways. First, a
trigger is only called when the attribute is set, as opposed to
See L<Moose::Manual::Delegation> for documentation on how to set up
delegation methods.
-=head2 Metaclass and traits
-
-One of Moose's best features is that it can be extended in all sorts
-of ways through the use of custom metaclasses and metaclass traits.
-
-When declaring an attribute, you can declare a metaclass or a set of
-traits for the attribute:
-
- use MooseX::AttributeHelpers;
-
- has 'mapping' => (
- metaclass => 'Collection::Hash',
- is => 'ro',
- default => sub { {} },
- );
+=head2 Attribute traits and metaclasses
-In this case, the metaclass C<Collection::Hash> really refers to
-L<MooseX::AttributeHelpers::Collection::Hash>.
+One of Moose's best features is that it can be extended in all sorts of ways
+through the use of metaclass traits and custom metaclasses.
-You can also apply one or more traits to an attribute:
+You can apply one or more traits to an attribute:
use MooseX::MetaDescription;
some examples. You can also write your own metaclasses and traits. See
the "Meta" and "Extending" recipes in L<Moose::Cookbook> for examples.
-=head1 ATTRIBUTE INHERITANCE
-
-By default, a child inherits all of its parent class(es)' attributes
-as-is. However, you can explicitly change some aspects of the
-inherited attribute in the child class.
-
-The options that can be overridden in a subclass are:
-
-=over 4
-
-=item * default
-
-=item * coerce
-
-=item * required
-
-=item * documentation
+=head2 Native Delegations
-=item * lazy
+Native delegations allow you to delegate to standard Perl data structures as
+if they were objects.
-=item * isa
+For example, we can pretend that an array reference has methods like
+C<push()>, C<shift()>, C<map()>, C<count()>, and more.
-=item * handles
-
-=item * builder
+ has 'options' => (
+ traits => ['Array'],
+ is => 'ro',
+ isa => 'ArrayRef[Str]',
+ default => sub { [] },
+ handles => {
+ all_options => 'elements',
+ add_option => 'push',
+ map_options => 'map',
+ option_count => 'count',
+ sorted_options => 'sort',
+ },
+ );
-=item * metaclass
+See L<Moose::Manual::Delegation> for more details.
-=item * traits
+=head1 ATTRIBUTE INHERITANCE
-=back
+By default, a child inherits all of its parent class(es)' attributes
+as-is. However, you can change most aspects of the inherited attribute in the
+child class. You cannot change any of its associated method names (reader,
+writer, predicate, etc).
To override an attribute, you simply prepend its name with a plus sign
(C<+>):
We recommend that you exercise caution when changing the type (C<isa>)
of an inherited attribute.
+=head1 MULTIPLE ATTRIBUTE SHORTCUTS
+
+If you have a number of attributes that differ only by name, you can declare
+them all at once:
+
+ package Point;
+
+ use Moose;
+
+ has [ 'x', 'y' ] => ( is => 'ro', isa => 'Int' );
+
+Also, because C<has> is just a function call, you can call it in a loop:
+
+ for my $name ( qw( x y ) ) {
+ my $builder = '_build_' . $name;
+ has $name => ( is => 'ro', isa => 'Int', builder => $builder );
+ }
+
=head1 MORE ON ATTRIBUTES
Moose attributes are a big topic, and this document glosses over a few
This option only works if your attribute is explicitly typed as an
C<ArrayRef> or C<HashRef>.
-However, we recommend that you use L<MooseX::AttributeHelpers> for
-these types of attributes, which gives you much more control over how
+However, we recommend that you use L<Moose::Meta::Attribute::Native> traits
+for these types of attributes, which gives you much more control over how
they are accessed and manipulated.
=head2 Initializer
-Moose provides an attribute option called C<initializer>. This is
-similar to C<builder>, except that it is I<only> called during object
-construction.
-
-This option is inherited from L<Class::MOP>, but we recommend that you
-use a C<builder> (which is Moose-only) instead.
+Moose provides an attribute option called C<initializer>. This is called when
+the attribute's value is being set in the constructor, and lets you change the
+value before it is set.
=head1 AUTHOR
=head1 COPYRIGHT AND LICENSE
-Copyright 2009 by Infinity Interactive, Inc.
+Copyright 2009-2010 by Infinity Interactive, Inc.
L<http://www.iinteractive.com>