Class::MOP::Attribute - Attribute Meta Object |
Class::MOP::Attribute - Attribute Meta Object
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 ));
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.
So, all 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.
$name
. All other
%options
are contained added as key-value pairs. Acceptable keys
are as follows:
-foo
, then the following code will Just Work.
MyClass->meta->construct_instance(-foo => "Hello There");
In an init_arg is not assigned, it will automatically use the
value of $name
. If an explicit undef
is given for an init_arg,
an attribute value can't be specified during initialization.
Class::MOP::Class::construct_instance
will initialize the
attribute to.
NOTE: 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:
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 default 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 Class::MOP::Class and this class to acheive it. However, this is currently left as an exercise to the reader :).
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 attribute initialization use the writer:
Class::MOP::Attribute->new('$some_attr' => ( writer => 'some_attr', initializer => 'some_attr', ));
Your writer will simply need to examine it's @_
and determine under
which context it is being called.
The accessor, reader, writer, predicate and clearer keys can contain either; the name of the method and an appropriate default one will be generated for you, or 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.
NOTE:
This method will properly handle the following code, by assigning an
undef
value to the attribute.
$object->set_something(undef);
NOTE:
This method will properly handle the following code, by assigning an
undef
value to the attribute.
$object->set_something();
1
) if the attribute has been set
to any value (even undef
), and false (0
) otherwise.
NOTE:
The predicate will return true even when you set an attribute's
value to undef
. 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.
If you really want to get rid of the value, you have to define and use a clearer (see below).
%options
supplied.
$instance
, the $params
passed are those that were
passed to the constructor.
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.
These methods are not for general use, and should only be used if you really know what you are doing.
$instance
has a value in it.
This is basically what the default predicate
method calls.
$instance
. This is basically what the default
clearer
would call. Note that this may be done even if the attirbute does not
have any associated read, write or clear methods.
These are all basic read-only value accessors for the values
passed into new
. I think they are pretty much self-explanitory.
If you pass in an $instance
argument to this accessor and the
default is a CODE reference, then the CODE reference will be
executed with the $instance
as its argument.
reader
and writer
or accessor
was used.
reader
and writer
or accessor
was specified or not.
NOTE: If no reader/writer/accessor was specified, this will use the attribute get_value/set_value methods, which can be very inefficient.
These are all basic predicate methods for the values passed into new
.
These methods allow you to manage the attributes association with the class that contains it. These methods should not be used lightly, nor are they very magical, they are mostly used internally and by metaclass instances.
$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
$class
. It is up to you to do this manually.
Class::MOP::Method::Accessor
. This method returns
the name of the accessor metaclass that this attribute uses.
$method
with the given attribute which is
used internally by the accessor generator.
associate_method
methods. This is a good way of seeing what
methods are used to manage a given attribute.
Class::MOP::Class::add_attribute
.
This method will call process_accessors
for each of the possible
method types (accessor, reader, writer & predicate).
$type
(accessor, reader, writer or predicate), and
a $value
(the value passed into the constructor for each of the
different types). It will then either generate the method itself
(using the generate_*_method
methods listed below) or it will
use the custom method passed through the constructor.
Class::MOP::Class::remove_attribute
.
NOTE: This does not currently remove methods from the list returned
by associated_methods
, that is on the TODO list.
It should also be noted that Class::MOP 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.
Stevan Little <stevan@iinteractive.com>
Copyright 2006-2008 by Infinity Interactive, Inc.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Class::MOP::Attribute - Attribute Meta Object |