X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FAttributes.pod;h=5ff0bb1c17ebc8289016e5296b5f093ae01a4eec;hb=66c87ce3bdc0e6caec3058561d278a7221d69f72;hp=58cd3c6a14da9dce8b1841852c67c345350b9a77;hpb=8d38e631864cd10b10a1eedafb82270f3942252c;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/Attributes.pod b/lib/Moose/Manual/Attributes.pod index 58cd3c6..5ff0bb1 100644 --- a/lib/Moose/Manual/Attributes.pod +++ b/lib/Moose/Manual/Attributes.pod @@ -1,25 +1,31 @@ -=pod +package Moose::Manual::Attributes; + +# ABSTRACT: Object attributes with Moose -=head1 NAME +__END__ -Moose::Manual::Attribute - Object attributes with Moose +=pod =head1 INTRODUCTION -Attributes are the most feature-rich part of Moose, and also one of -the most useful. It's easy to imagine a class without roles or method -modifiers, but almost every class has attributes. +Moose attributes have many properties, and attributes are probably the +single most powerful and flexible part of Moose. You can create a +powerful class simply by declaring attributes. In fact, it's possible +to have classes that consist solely of attribute declarations. -Attributes are properties that every member of a class has. For -example, we might say that "every Person object has a first name and -last name. Attributes can be optional, so that we can say "some Person +An attribute is a property that every member of a class has. For +example, we might say that "every C object has a first name and +last name". Attributes can be optional, so that we can say "some C objects have a social security number (and some don't)". -At its simplest, an attribute can be thought of slot in hash that can -be read and set. However, attributes, can also have things like -default values, laziness, type constraints, delegation and much more. +At its simplest, an attribute can be thought of as a named value (as +in a hash) that can be read and set. However, attributes can also have +defaults, type constraints, delegation and much more. + +In other languages, attributes are also referred to as slots or +properties. -=head1 ATTRIBUTE 101 +=head1 ATTRIBUTE OPTIONS Use the C function to declare an attribute: @@ -29,79 +35,83 @@ Use the C function to declare an attribute: has 'first_name' => ( is => 'rw' ); -This says that all person objects have an optional "first_name" -attribute that can be both read and set on the object. +This says that all C objects have an optional read-write +"first_name" attribute. -=head2 Read-write Vs Read-only +=head2 Read-write vs. read-only -The code inside the parentheses defines the details of the -attribute. There are a lot of options you can put here, but in the -simplest form you just need to include C, which can be either -C (read-write) or C (read-only). +The options passed to C define the properties of the attribute. There are +many options, but in the simplest form you just need to set C, which can +be either C (read-only) or C (read-write). When an attribute is C, +you can change it by passing a value to its accessor. When an attribute is +C, you may only read the current value of the attribute. -(In fact, you could even omit C, but that leaves you with an -attribute that has no accessors, which is pointless unless you're -doing some deep, dark magic). +In fact, you could even omit C, but that gives you an attribute +that has no accessor. This can be useful with other attribute options, +such as C. However, if your attribute generates I +accessors, Moose will issue a warning, because that usually means the +programmer forgot to say the attribute is read-only or read-write. If +you really mean to have no accessors, you can silence this warning by +setting C to C. -=head2 Accessor Methods +=head2 Accessor methods Each attribute has one or more accessor methods. An accessor lets you -read and write the value of the attribute for an object. +read and write the value of that attribute for an object. By default, the accessor method has the same name as the attribute. If you declared your attribute as C then your accessor will be -read-only. If you declared it read-write, you get a read-write +read-only. If you declared it as C, you get a read-write accessor. Simple. -So with our Person example above, we now have a single C -accessor that can set or return a person object's first name. +Given our C example above, we now have a single C +accessor that can read or write a C object's C +attribute's value. If you want, you can also explicitly specify the method names to be -used for getting and setting an attribute's value. This is -particularly handy when you'd like an attribute to be publically +used for reading and writing an attribute's value. This is +particularly handy when you'd like an attribute to be publicly readable, but only privately settable. For example: - has 'weight' => - ( is => 'rw', - writer => '_set_weight', - ); + has 'weight' => ( + is => 'ro', + writer => '_set_weight', + ); -This might be useful if weight is calculated based on other methods, -for example every time the C method is called, we might adjust +This might be useful if weight is calculated based on other methods. +For example, every time the C method is called, we might adjust weight. This lets us hide the implementation details of weight changes, but still provide the weight value to users of the class. -Some people might prefer to have distinct methods for getting and -setting, even when setting is a public method. In I, Damian Conway recommends that getter methods start with -"get_" and setter methods start with "set_". +Some people might prefer to have distinct methods for reading and +writing. In I, Damian Conway recommends that +reader methods start with "get_" and writer methods start with "set_". We can do exactly that by providing names for both the C and C methods: - has 'weight' => - ( is => 'rw', - reader => 'get_weight', - writer => 'set_weight', - ); + has 'weight' => ( + is => 'rw', + reader => 'get_weight', + writer => 'set_weight', + ); If you're thinking that doing this over and over would be insanely tedious, you're right! Fortunately, Moose provides a powerful -extension system that lets you do things like override the default -accessor method conventions. See L for more -details. +extension system that lets you override the default naming +conventions. See L for more details. -=head2 Predicate and Clearer Methods +=head2 Predicate and clearer methods -Moose is able to explicitly distinguish between false or undefined -values, and an attribute which is not set. If you want to be able to -access and manipulate these states, you also need to define clearer -and predicate methods for your attributes. +Moose allows you to explicitly distinguish between a false or +undefined attribute value and an attribute which has not been set. If +you want to access this information, you must define clearer and +predicate methods for an attribute. -A predicate method can be used to determine whether or not a given -attribute is currently set. Note that even if the attribute was -explicitly set to undef or some other false value, the predicate will -return true. +A predicate method tells you whether or not a given attribute is +currently set. Note that an attribute can be explicitly set to +C or some other false value, but the predicate will return +true. The clearer method unsets the attribute. This is I the same as setting the value to C, but you can only distinguish @@ -114,11 +124,11 @@ predicate, and clearer method. use Moose; - has 'ssn' => - ( is => 'rw', - clearer => 'clear_ssn', - predicate => 'has_ssn', - ); + has 'ssn' => ( + is => 'rw', + clearer => 'clear_ssn', + predicate => 'has_ssn', + ); ... @@ -140,184 +150,478 @@ predicate, and clearer method. my $person2 = Person->new( ssn => '111-22-3333'); $person2->has_ssn; # true -Note that by default, Moose does not make a predicate or clearer for -you. You have to explicitly provide a method name for the ones you -want. +By default, Moose does not make a predicate or clearer for you. You must +explicitly provide names for them, and then Moose will create the methods +for you. -=head2 Required or Not? +=head2 Required or not? -By default, all attributes are optional. That means that they do not -need to be provided at object construction time. If you want to make -an attribute required, simply set the required option to true: +By default, all attributes are optional, and do not need to be +provided at object construction time. If you want to make an attribute +required, simply set the C option to true: - has 'name' => - ( is => 'rw', - required => 1, - ); + has 'name' => ( + is => 'ro', + required => 1, + ); There are a couple caveats worth mentioning in regards to what -required actually means. +"required" actually means. -Basically, all it says is that this attribute must be provided to the -constructor. It does not say anything about its value, so it could be -C. +Basically, all it says is that this attribute (C) must be provided to +the constructor, or be lazy with either a default or a builder. It does not +say anything about its value, so it could be C. If you define a clearer method on a required attribute, the clearer -I work. So even though something is defined as required, you can -remove it after object construction. +I work, so even a required attribute can be unset after object +construction. -So if you do make an attribute required, that probably means that -providing a clearer doesn't make much sense. In some cases, it might -be handy to have a I clearer and predicate for a required +This means that if you do make an attribute required, providing a +clearer doesn't make much sense. In some cases, it might be handy to +have a I C and C for a required attribute. -=head2 Default and Builder Methods +=head2 Default and builder methods -Attributes can have default values, and there are several ways to -specify this. +Attributes can have default values, and Moose provides two ways to +specify that default. In the simplest form, you simply provide a non-reference scalar value -for the "default" option: +for the C option: - has 'size' => - ( is => 'rw', - default => 'medium', - predicate => 'has_size', - ); + has 'size' => ( + is => 'ro', + default => 'medium', + predicate => 'has_size', + ); If the size attribute is not provided to the constructor, then it ends -up being set to "medium": +up being set to C: my $person = Person->new(); $person->size; # medium $person->has_size; # true -You can also provide a subroutine reference for default. This -reference will be called a method on the object. +You can also provide a subroutine reference for C. This +reference will be called as a method on the object. - has 'size' => - ( is => 'rw', - default => - sub { ('small', 'medium', 'large')[ int( rand 3 ) ] }, - predicate => 'has_size', - ); + has 'size' => ( + is => 'ro', + default => + sub { ( 'small', 'medium', 'large' )[ int( rand 3 ) ] }, + 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. -Of course, if it's called during object construction, it may be before -other attributes have been set. If your default is dependent on other -parts of the object's state, you can make the default lazy, which is -covered in the next section. +When you provide a C subroutine reference, it is called as a +method on the object, with no additional parameters: + + has 'size' => ( + is => 'ro', + default => sub { + my $self = shift; + + return $self->height > 200 ? 'large' : 'average'; + }, + ); + +When the C is called during object construction, it may be +called before other attributes have been set. If your default is +dependent on other parts of the object's state, you can make the +attribute C. 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 => 'rw', - default => {}, # wrong! - ); + 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', + default => {}, # wrong! + ); + +Moose will throw an error if you pass a bare non-subroutine reference +as the default. 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 => 'rw', - 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 builder method for your attribute: +As an alternative to using a subroutine reference, you can supply a C +method for your attribute: - has 'size' => - ( is => 'rw', - builder => '_build_size', - predicate => 'has_size', - ); + has 'size' => ( + is => 'ro', + builder => '_build_size', + predicate => 'has_size', + ); sub _build_size { - return ('small', 'medium', 'large')[ int( rand 3 ) ]; + 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. Second, the C<_build_size> method can be overridden in -subclasses. +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 method, it can be subclassed or provided by a role. + +We strongly recommend that you use a C instead of a +C for anything beyond the most trivial default. + +A C, just like a C, is called as a method on the +object with no additional parameters. + +=head3 Builders allow subclassing + +Because the C is called I, it goes through Perl's +method resolution. This means that builder methods are both +inheritable and overridable. + +If we subclass our C class, we can override C<_build_size>: + + package Lilliputian; + + use Moose; + extends 'Person'; + + sub _build_size { return 'small' } + +=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 +consuming class provide the C: + + package HasSize; + use Moose::Role; + + requires '_build_size'; + + has 'size' => ( + is => 'ro', + lazy => 1, + builder => '_build_size', + ); + + package Lilliputian; + use Moose; + + with 'HasSize'; -We strongly recommend that you use a builder instead of a default for -anything beyond the most trivial default. + sub _build_size { return 'small' } -=head2 Laziness and lazy_build +Roles are covered in L. -Moose lets you defer attribute population by making an attribute lazy: +=head2 Laziness - has 'size' => - ( is => 'rw', - lazy => 1, - builder => '_build_size', - ); +Moose lets you defer attribute population by making an attribute +C: -When the lazy option is true, the attribute is not populated until the -reader method is called, rather than at object construction -time. There are several reasons you might choose to do this. + has 'size' => ( + is => 'ro', + lazy => 1, + builder => '_build_size', + ); + +When C is true, the default is not generated until the reader +method is called, rather than at object construction time. There are +several reasons you might choose to do this. First, if the default value for this attribute depends on some other -attributes, then the attribute I be lazy. During object -construction, default subroutine references are not called in any -particular order, so you cannot count on other attribute being -populated at that time. +attributes, then the attribute I be C. During object +construction, defaults are not generated in a predictable order, so +you cannot count on some other attribute being populated when +generating a default. -Second, there's often no reason to spend program time calculating a -default before its needed. Making an attribute lazy lets you defer the -cost until the attribute is needed. If the attribute is I -needed, you save some CPU time. +Second, there's often no reason to calculate a default before it's +needed. Making an attribute C lets you defer the cost until the +attribute is needed. If the attribute is I needed, you save +some CPU time. We recommend that you make any attribute with a builder or non-trivial -default lazy as a matter of course. +default C as a matter of course. + +=head2 Constructor parameters (C) + +By default, each attribute can be passed by name to the class's +constructor. On occasion, you may want to use a different name for +the constructor parameter. You may also want to make an attribute +unsettable via the constructor. + +You can do either of these things with the C option: + + has 'bigness' => ( + is => 'ro', + init_arg => 'size', + ); + +Now we have an attribute named "bigness", but we pass C to the +constructor. + +Even more useful is the ability to disable setting an attribute via +the constructor. This is particularly handy for private attributes: + + has '_genetic_code' => ( + is => 'ro', + lazy => 1, + builder => '_build_genetic_code', + init_arg => undef, + ); + +By setting the C to C, we make it impossible to set +this attribute when creating a new object. + +=head2 Weak references + +Moose has built-in support for weak references. If you set the +C option to a true value, then it will call +C whenever the attribute is set: + + has 'parent' => ( + is => 'rw', + weak_ref => 1, + ); + + $node->parent($parent_node); + +This is very useful when you're building objects that may contain +circular references. + +When the object in a weak references goes out of scope, the attribute's value +will become C "behind the scenes". This is done by the Perl interpreter +directly, so Moose does not see this change. This means that triggers don't +fire, coercions aren't applied, etc. + +The attribute is not cleared, so a predicate method for that attribute will +still return true. Similarly, when the attribute is next accessed, a default +value will not be generated. + +=head2 Triggers + +A C is a subroutine that is called whenever the attribute is +set: + + has 'size' => ( + is => 'rw', + trigger => \&_size_set, + ); + + sub _size_set { + my ( $self, $size, $old_size ) = @_; + + my $msg = $self->name; + + if ( @_ > 2 ) { + $msg .= " - old size was $old_size"; + } + + $msg .= " - size is now $size"; + warn $msg; + } + +The trigger is called I 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. + +This differs from an C method modifier in two ways. First, a +trigger is only called when the attribute is set, as opposed to +whenever the accessor method is called (for reading or +writing). Second, it is also called when an attribute's value is +passed to the constructor. + +However, triggers are I called when an attribute is populated +from a C or C. + +=head2 Attribute types + +Attributes can be restricted to only accept certain types: + + has 'first_name' => ( + is => 'ro', + isa => 'Str', + ); + +This says that the C attribute must be a string. + +Moose also provides a shortcut for specifying that an attribute only +accepts objects that do a certain role: + + has 'weapon' => ( + is => 'rw', + does => 'MyApp::Weapon', + ); + +See the L documentation for a complete +discussion of Moose's type system. + +=head2 Delegation + +An attribute can define methods which simply delegate to its value: + + has 'hair_color' => ( + is => 'ro', + isa => 'Graphics::Color::RGB', + handles => { hair_color_hex => 'as_hex_string' }, + ); + +This adds a new method, C. When someone calls +C, internally, the object just calls C<< +$self->hair_color->as_hex_string >>. + +See L for documentation on how to set up +delegation methods. + +=head2 Attribute traits and metaclasses + +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 apply one or more traits to an attribute: + + use MooseX::MetaDescription; + + has 'size' => ( + is => 'ro', + traits => ['MooseX::MetaDescription::Meta::Trait'], + description => { + html_widget => 'text_input', + serialize_as => 'element', + }, + ); + +The advantage of traits is that you can mix more than one of them +together easily (in fact, a trait is just a role under the hood). + +There are a number of MooseX modules on CPAN which provide useful +attribute metaclasses and traits. See L for +some examples. You can also write your own metaclasses and traits. See +the "Meta" and "Extending" recipes in L for examples. + +=head2 Native Delegations + +Native delegations allow you to delegate to standard Perl data structures as +if they were objects. + +For example, we can pretend that an array reference has methods like +C, C, C, C, and more. + + 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', + }, + ); + +See L for more details. + +=head1 ATTRIBUTE INHERITANCE + +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<+>): + + package LazyPerson; + + use Moose; + + extends 'Person'; + + has '+first_name' => ( + lazy => 1, + default => 'Bill', + ); + +Now the C attribute in C is lazy, and defaults +to C<'Bill'>. + +We recommend that you exercise caution when changing the type (C) +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 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 +aspects. We recommend that you read the L +and L documents to get a more complete +understanding of attribute features. + +=head1 A FEW MORE OPTIONS + +Moose has lots of attribute options. The ones listed below are +superseded by some more modern features, but are covered for the sake +of completeness. + +=head2 The C option + +You can provide a piece of documentation as a string for an attribute: -To facilitate this, you can simply specify the C attribute -option. This bundles up a number of options together: + has 'first_name' => ( + is => 'rw', + documentation => q{The person's first (personal) name}, + ); - has 'size' => - ( is => 'rw', - lazy_build => 1, - ); +Moose does absolutely nothing with this information other than store +it. -This is the same as specifying all of these options: +=head2 The C option - has 'size' => - ( is => 'rw', - lazy => 1, - builder => '_build_size', - clearer => 'clear_size', - predicate => 'has_size', - ); +If your attribute is an array reference or hash reference, the +C option will make Moose dereference the value when it is +returned from the reader method: -If your attribute name starts with an underscore (_), then the clearer -and predicate will as well: + my %map = $object->mapping; - has '_size' => - ( is => 'rw', - lazy_build => 1, - ); +This option only works if your attribute is explicitly typed as an +C or C. -becomes ... +However, we recommend that you use L traits +for these types of attributes, which gives you much more control over how +they are accessed and manipulated. See also +L. - has '_size' => - ( is => 'rw', - lazy => 1, - builder => '_build__size', - clearer => '_clear_size', - predicate => '_has_size', - ); +=head2 Initializer -Note the doubled underscore in the builder name. The lazy_build simply -prepends the attribute name with "_build_" to come up with the builder -name. +Moose provides an attribute option called C. This is called when +the attribute's value is being set in the constructor, and lets you change the +value before it is set. -=head2 Private Attributes +=cut