From: Dave Rolsky Date: Thu, 12 Mar 2009 18:59:44 +0000 (-0500) Subject: Revamped the docs for Class::MOP::Attribute X-Git-Tag: 0.78_01~56 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=2e23f7dc15a9046833c9db769ab78293b768e5fc;p=gitmo%2FClass-MOP.git Revamped the docs for Class::MOP::Attribute --- diff --git a/lib/Class/MOP/Attribute.pm b/lib/Class/MOP/Attribute.pm index 89d5703..aa112c2 100644 --- a/lib/Class/MOP/Attribute.pm +++ b/lib/Class/MOP/Attribute.pm @@ -446,30 +446,33 @@ Class::MOP::Attribute - Attribute Meta Object =head1 SYNOPSIS - Class::MOP::Attribute->new( foo => ( - accessor => 'foo', # dual purpose get/set accessor - predicate => 'has_foo' # predicate check for defined-ness - init_arg => '-foo', # class->new will look for a -foo key - default => 'BAR IS BAZ!' # if no -foo key is provided, use this - )); - - Class::MOP::Attribute->new( bar => ( - reader => 'bar', # getter - writer => 'set_bar', # setter - predicate => 'has_bar' # predicate check for defined-ness - init_arg => ':bar', # class->new will look for a :bar key - # no default value means it is undef - )); + Class::MOP::Attribute->new( + foo => ( + accessor => 'foo', # dual purpose get/set accessor + predicate => 'has_foo', # predicate check for defined-ness + init_arg => '-foo', # class->new will look for a -foo key + default => 'BAR IS BAZ!' # if no -foo key is provided, use this + ) + ); + + Class::MOP::Attribute->new( + bar => ( + reader => 'bar', # getter + writer => 'set_bar', # setter + predicate => 'has_bar', # predicate check for defined-ness + init_arg => ':bar', # class->new will look for a :bar key + # no default value means it is undef + ) + ); =head1 DESCRIPTION -The Attribute Protocol is almost entirely an invention of this module, -and is completely optional to this MOP. This is because Perl 5 does not -have consistent notion of what is an attribute of a class. There are -so many ways in which this is done, and very few (if any) are -easily discoverable by this module. +The Attribute Protocol is almost entirely an invention of +C. Perl 5 does not have a consistent notion of +attributes. There are so many ways in which this is done, and very few +(if any) are easily discoverable by this module. -So, all that said, this module attempts to inject some order into this +With that said, this module attempts to inject some order into this chaos, by introducing a consistent API which can be used to create object attributes. @@ -479,315 +482,336 @@ object attributes. =over 4 -=item B +=item B<< Class::MOP::Attribute->new($name, ?%options) >> An attribute must (at the very least), have a C<$name>. All other -C<%options> are contained added as key-value pairs. Acceptable keys -are as follows: +C<%options> are added as key-value pairs. -=over 4 +=over 8 =item I -This should be a string value representing the expected key in -an initialization hash. For instance, if we have an I -value of C<-foo>, then the following code will Just Work. +This is a string value representing the expected key in an +initialization hash. For instance, if we have an C value of +C<-foo>, then the following code will Just Work. - MyClass->meta->construct_instance(-foo => "Hello There"); + MyClass->meta->construct_instance( -foo => 'Hello There' ); -In an init_arg is not assigned, it will automatically use the -value of C<$name>. If an explicit C is given for an init_arg, -an attribute value can't be specified during initialization. +If an init_arg is not assigned, it will automatically use the +attribute's name. If C is explicitly set to C, the +attribute cannot be specified during initialization. =item I -The value of this key is the name of the method that will be -called to obtain the value used to initialize the attribute. -This should be a method in the class associated with the attribute, -not a method in the attribute class itself. +This provides the name of a method that will be called to initialize +the attribute. This method will be called on the object after it is +constructed. It is expected to return a valid value for the attribute. =item I -The value of this key is the default value which -C will initialize the -attribute to. +This can be used to provide an explicit default for initializing the +attribute. If the default you provide is a subroutine reference, then +this reference will be called I on the object. -B -If the value is a simple scalar (string or number), then it can -be just passed as is. However, if you wish to initialize it with -a HASH or ARRAY ref, then you need to wrap that inside a CODE -reference, like so: +If the value is a simple scalar (string or number), then it can be +just passed as is. However, if you wish to initialize it with a HASH +or ARRAY ref, then you need to wrap that inside a subroutine +reference: - Class::MOP::Attribute->new('@foo' => ( - default => sub { [] }, - )); + Class::MOP::Attribute->new( + 'foo' => ( + default => sub { [] }, + ) + ); # or ... - Class::MOP::Attribute->new('%foo' => ( - default => sub { {} }, - )); - -If you wish to initialize an attribute with a CODE reference -itself, then you need to wrap that in a subroutine as well, like -so: - - Class::MOP::Attribute->new('&foo' => ( - default => sub { sub { print "Hello World" } }, - )); - -And lastly, if the value of your attribute is dependent upon -some other aspect of the instance structure, then you can take -advantage of the fact that when the I value is a CODE -reference, it is passed the (as yet unfinished) instance structure -as it's only argument. So you can do things like this: - - Class::MOP::Attribute->new('$object_identity' => ( - default => sub { Scalar::Util::refaddr($_[0]) }, - )); - -This last feature is fairly limited as there is no gurantee of -the order of attribute initializations, so you cannot perform -any kind of dependent initializations. However, if this is -something you need, you could subclass B and -this class to acheive it. However, this is currently left as -an exercise to the reader :). + Class::MOP::Attribute->new( + 'foo' => ( + default => sub { {} }, + ) + ); + +If you wish to initialize an attribute with a subroutine reference +itself, then you need to wrap that in a subroutine as well: + + Class::MOP::Attribute->new( + 'foo' => ( + default => sub { + sub { print "Hello World" } + }, + ) + ); + +And lastly, if the value of your attribute is dependent upon some +other aspect of the instance structure, then you can take advantage of +the fact that when the C value is called as a method: + + Class::MOP::Attribute->new( + 'object_identity' => ( + default => sub { Scalar::Util::refaddr( $_[0] ) }, + ) + ); + +Note that there is no guarantee that attributes are initialized in any +particular order, so you cannot rely on the value of some other +attribute when generating the default. =item I -This may be a method name (referring to a method on the class with this -attribute) or a CODE ref. The initializer is used to set the attribute value -on an instance when the attribute is set during instance initialization. When -called, it is passed the instance (as the invocant), the value to set, a -slot-setting CODE ref, and the attribute meta-instance. The slot-setting code -is provided to make it easy to set the (possibly altered) value on the instance -without going through several more method calls. - -This contrived example shows an initializer that sets the attribute to twice -the given value. - - Class::MOP::Attribute->new('$doubled' => ( - initializer => sub { - my ($instance, $value, $set) = @_; - $set->($value * 2); - }, - )); - -As method names can be given as initializers, one can easily make +This option can be either a method name or a subroutine +reference. This method will be called when setting the attribute's +value in the constructor. Unlike C and C, the +initializer is only called when a value is provided to the +constructor. The initializer allows you to munge this value during +object construction. + +The initializer is called as a method with three arguments. The first +is the value that was passed to the constructor. The second is a +subroutine reference that can be called to actually set the +attribute's value, and the last is the associated +C object. + +This contrived example shows an initializer that sets the attribute to +twice the given value. + + Class::MOP::Attribute->new( + 'doubled' => ( + initializer => sub { + my ( $instance, $value, $set ) = @_; + $set->( $value * 2 ); + }, + ) + ); + +Since an initializer can be a method name, you can easily make attribute initialization use the writer: - Class::MOP::Attribute->new('$some_attr' => ( - writer => 'some_attr', - initializer => 'some_attr', - )); + Class::MOP::Attribute->new( + 'some_attr' => ( + writer => 'some_attr', + initializer => 'some_attr', + ) + ); -Your writer will simply need to examine it's C<@_> and determine under -which context it is being called. +Your writer will need to examine C<@_> and determine under which +context it is being called. =back -The I, I, I, I and I keys can -contain either; the name of the method and an appropriate default one will be -generated for you, B a HASH ref containing exactly one key (which will be -used as the name of the method) and one value, which should contain a CODE -reference which will be installed as the method itself. +The C, C, C, C and C +options all accept the same parameters. You can provide the name of +the method, in which case an appropriate default method will be +generated for you. Or instead you can also provide hash reference +containing exactly one key (the method name) and one value. The value +should be a subroutine reference, which will be installed as the +method itself. =over 4 =item I -The I is a standard perl-style read/write accessor. It will -return the value of the attribute, and if a value is passed as an argument, -it will assign that value to the attribute. +An C is a standard Perl-style read/write accessor. It will +return the value of the attribute, and if a value is passed as an +argument, it will assign that value to the attribute. -B -This method will properly handle the following code, by assigning an -C value to the attribute. +Note that C is a legitimate value, so this will work: $object->set_something(undef); =item I -This is a basic read-only accessor, it will just return the value of -the attribute. +This is a basic read-only accessor. It returns the value of the +attribute. =item I This is a basic write accessor, it accepts a single argument, and -assigns that value to the attribute. This method does not intentially -return a value, however perl will return the result of the last -expression in the subroutine, which returns in this returning the -same value that it was passed. +assigns that value to the attribute. -B -This method will properly handle the following code, by assigning an -C value to the attribute. +Note that C is a legitimate value, so this will work: - $object->set_something(); + $object->set_something(undef); =item I -This is a basic test to see if any value has been set for the -attribute. It will return true (C<1>) if the attribute has been set -to any value (even C), and false (C<0>) otherwise. - -B -The predicate will return true even when you set an attribute's -value to C. This behaviour has changed as of version 0.43. In -older versions, the predicate (erroneously) checked for attribute -value definedness, instead of presence as it is now. +The predicate method returns a boolean indicating whether or not the +attribute has been explicitly set. -If you really want to get rid of the value, you have to define and -use a I (see below). +Note that the predicate returns true even if the attribute was set to +a false value (C<0> or C). =item I -This is the a method that will uninitialize the attr, reverting lazy values -back to their "unfulfilled" state. +This method will uninitialize the attribute. After an attribute is +cleared, its C will return false. =back -=item B +=item B<< $attr->clone(%options) >> -This will return a clone of the attribute instance, allowing the overriding -of various attributes through the C<%options> supplied. +This clones the attribute. Any options you provide will override the +settings of the original attribute. You can change the name of the new +attribute by passing a C key in C<%options>. -=item B +=back -This method is used internally to initialize the approriate slot for this -attribute in a given C<$instance>, the C<$params> passed are those that were -passed to the constructor. +=head2 Informational -=back +These are all basic read-only accessors for the values passed into +the constructor. -=head2 Value management +=over 4 -These methods are basically "backdoors" to the instance, which can be used -to bypass the regular accessors, but still stay within the context of the MOP. +=item B<< $attr->name >> -These methods are not for general use, and should only be used if you really -know what you are doing. +=item B<< $attr->accessor >> -=over 4 +=item B<< $attr->reader >> -=item B +=item B<< $attr->writer >> -Set the value without going through the accessor. Note that this may be done to -even attributes with just read only accessors. +=item B<< $attr->predicate >> -=item B +=item B<< $attr->clearer >> -This method sets the value without going through the accessor -- but it is only -called when the instance data is first initialized. +The C, C, C, C, and C +methods all return exactly what was passed to the constructor, so it +can be either a string containing a method name, or a hash refrence. -=item B +=item B<< $attr->initializer >> -Return the value without going through the accessor. Note that this may be done -even to attributes with just write only accessors. +Returns the intializer as passed to the constructor, so this may be +either a method name or a subroutine reference. -=item B +=item B<< $attr->init_arg >> -Return a boolean indicating if the item in the C<$instance> has a value in it. -This is basically what the default C method calls. +=item B<< $attr->is_default_a_coderef >> -=item B +=item B<< $attr->default($instance) >> -This will clear the value in the C<$instance>. This is basically what the default -C would call. Note that this may be done even if the attirbute does not -have any associated read, write or clear methods. +The C<$instance> argument is optional. If you don't pass it, the +return value for this method is exactly what was passed to the +constructor, either a simple scalar or a subroutine reference. -=back +If you I pass an C<$instance> and the default is a subroutine +reference, then the reference is called as a method on the +C<$instance> and the generated value is returned. -=head2 Informational +=item B<< $attr->slots >> -These are all basic read-only value accessors for the values -passed into C. I think they are pretty much self-explanitory. +Return a list of slots required by the attribute. This is usually just +one, the name of the attribute. -=over 4 +A slot is the name of the hash key used to store the attribute in an +object instance. -=item B +=item B<< $attr->get_read_method >> -=item B +=item B<< $attr->get_write_method >> -=item B +Returns the name of a method suitable for reading or writing the value +of the attribute in the associated class. -=item B +If an attribute is read- or write-only, then these methods can return +C as appropriate. -=item B +=item B<< $attr->has_read_method >> -=item B +=item B<< $attr->has_write_method >> -=item B +This returns a boolean indicating whether the attribute has a I +read or write method. -=item B +=item B<< $attr->get_read_method_ref >> -=item B +=item B<< $attr->get_write_method_ref >> -=item B +Returns the subroutine reference of a method suitable for reading or +writing the attribute's value in the associated class. These methods +always return a subroutine reference, regardless of whether or not the +attribute is read- or write-only. + +=back -Return the default value for the attribute. +=head2 Informational predicates -If you pass in an C<$instance> argument to this accessor and the -I is a CODE reference, then the CODE reference will be -executed with the C<$instance> as its argument. +These are all basic predicate methods for the values passed into C. -=item B +=over 4 -Return a list of slots required by the attribute. This is usually -just one, which is the name of the attribute. +=item B<< $attr->has_accessor >> -=item B +=item B<< $attr->has_reader >> -=item B +=item B<< $attr->has_writer >> -Return the name of a method name suitable for reading / writing the value -of the attribute in the associated class. Suitable for use whether -C and C or C was used. +=item B<< $attr->has_predicate >> -=item B +=item B<< $attr->has_clearer >> -=item B +=item B<< $attr->has_initializer >> -Return the CODE reference of a method suitable for reading / writing the -value of the attribute in the associated class. Suitable for use whether -C and C or C was specified or not. +=item B<< $attr->has_init_arg >> -NOTE: If no reader/writer/accessor was specified, this will use the -attribute get_value/set_value methods, which can be very inefficient. +This will be I if the C was set to C. -=item B +=item B<< $attr->has_default >> -=item B +This will be I if the C was set to C, since +C is the default C anyway. -Return whether a method exists suitable for reading / writing the value -of the attribute in the associated class. Suitable for use whether -C and C or C was used. +=item B<< $attr->has_builder >> =back -=head2 Informational predicates +=head2 Value management -These are all basic predicate methods for the values passed into C. +These methods are basically "backdoors" to the instance, and can be +used to bypass the regular accessors, but still stay within the MOP. + +These methods are not for general use, and should only be used if you +really know what you are doing. =over 4 -=item B +=item B<< $attr->initialize_instance_slot($meta_instance, $instance, $params) >> + +This method is used internally to initialize the attribute's slot in +the object C<$instance>. + +The C<$params> is a hash reference of the values passed to the object +constructor. + +It's unlikely that you'll need to call this method yourself. -=item B +=item B<< $attr->set_value($instance, $value) >> -=item B +Sets the value without going through the accessor. Note that this +works even with read-only attributes. -=item B +=item B<< $attr->set_initial_value($instance, $value) >> -=item B +Sets the value without going through the accessor. This method is only +called when the instance is first being initialized. -=item B +=item B<< $attr->get_value($instance) >> -=item B +Returns the value without going through the accessor. Note that this +works even with write-only accessors. -=item B +=item B<< $attr->has_value($instance) >> -=item B +Return a boolean indicating whether the attribute has been set in +C<$instance>. This how the default C method works. + +=item B<< $attr->clear_value($instance) >> + +This will clear the attribute's value in C<$instance>. This is what +the default C calls. + +Note that this works even if the attribute does not have any +associated read, write or clear methods. =back @@ -800,24 +824,32 @@ and by metaclass instances. =over 4 -=item B +=item B<< $attr->associated_class >> + +This returns the C with which this attribute is +associated, if any. + +=item B<< $attr->attach_to_class($metaclass) >> -This returns the metaclass this attribute is associated with. +This method stores a weakened reference to the C<$metaclass> object +internally. -=item B +This method does not remove the attribute from its old class, +nor does it create any accessors in the new class. -This will store a weaken reference to C<$class> internally. You should -note that just changing the class assocation will not remove the attribute -from it's old class, and initialize it (and it's accessors) in the new -C<$class>. It is up to you to do this manually. +It is probably best to use the L C +method instead. -=item B +=item B<< $attr->detach_from_class >> -This will remove the weakened reference to the class. It does B -remove the attribute itself from the class (or remove it's accessors), -you must do that yourself if you want too. Actually if that is what -you want to do, you should probably be looking at -L instead. +This method removes the associate metaclass object from the attribute +it has one. + +This method does not remove the attribute itself from the class, or +remove its accessors. + +It is probably best to use the L +C method instead. =back @@ -825,48 +857,52 @@ L instead. =over 4 -=item B +=item B<< $attr->accessor_metaclass >> -Accessors are generated by an accessor metaclass, which is usually -a subclass of C. This method returns +Accessor methods are generated using an accessor metaclass. By +default, this is L. This method returns the name of the accessor metaclass that this attribute uses. -=item B +=item B<< $attr->associate_method($method) >> -This will associate a C<$method> with the given attribute which is -used internally by the accessor generator. +This associates a L object with the +attribute. Typically, this is called internally when an attribute +generates its accessors. -=item B +=item B<< $attr->associated_methods >> -This will return the list of methods which have been associated with -the C methods. This is a good way of seeing what -methods are used to manage a given attribute. +This returns the list of methods which have been associated with the +attribute. -=item B +=item B<< $attr->install_accessors >> -This allows the attribute to generate and install code for it's own -I methods. This is called by -C. +This method generates and installs code the attributes various +accessors. It is typically called from the L +C method. -This method will call C for each of the possible -method types (accessor, reader, writer & predicate). +This method will call C<< $attr->process_accessors >> for each of the +possible method types (accessor, reader, writer & predicate). -=item B +=item B<< $attr->process_accessors($type, $value) >> -This takes a C<$type> (accessor, reader, writer or predicate), and +This method takes a C<$type> (accessor, reader, writer or predicate), and a C<$value> (the value passed into the constructor for each of the -different types). It will then either generate the method itself -(using the C methods listed below) or it will -use the custom method passed through the constructor. +different types). + +It will then either generate the method itself (using the +C methods listed below) or it will use the custom +method passed through the constructor. + +This method is mostly intended for internal use from the C<< +$attr->install_accessors >> method. -=item B +=item B<< $attr->remove_accessors >> -This allows the attribute to remove the method for it's own -I. This is called by -C. +This method removes all of the accessors associated with the +attribute. -NOTE: This does not currently remove methods from the list returned -by C, that is on the TODO list. +This does not currently remove methods from the list returned by +C. =back @@ -874,15 +910,13 @@ by C, that is on the TODO list. =over 4 -=item B +=item B<< $attr->meta >> -This will return a B instance which is related -to this class. +This will return a L instance for this class. -It should also be noted that B will actually bootstrap -this module by installing a number of attribute meta-objects into -it's metaclass. This will allow this class to reap all the benefits -of the MOP when subclassing it. +It should also be noted that L will actually bootstrap +this module by installing a number of attribute meta-objects into its +metaclass. =back