X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FMOP%2FAttribute.pm;h=0cb31c853162a4e91c57f6c27af27b5d56f875ac;hb=8ee74136c5d5c5a6416844e7238898f47b00f553;hp=df0fb3cec08000530dd746935b3da005052a3107;hpb=93b4e576d3ac26a1676c45177161c6477ac2b35e;p=gitmo%2FClass-MOP.git diff --git a/lib/Class/MOP/Attribute.pm b/lib/Class/MOP/Attribute.pm index df0fb3c..0cb31c8 100644 --- a/lib/Class/MOP/Attribute.pm +++ b/lib/Class/MOP/Attribute.pm @@ -4,53 +4,81 @@ package Class::MOP::Attribute; use strict; use warnings; +use Class::MOP::Method::Accessor; + use Carp 'confess'; use Scalar::Util 'blessed', 'reftype', 'weaken'; -our $VERSION = '0.07'; +our $VERSION = '0.23'; +our $AUTHORITY = 'cpan:STEVAN'; + +use base 'Class::MOP::Object'; -sub meta { +sub meta { require Class::MOP::Class; Class::MOP::Class->initialize(blessed($_[0]) || $_[0]); } # NOTE: (meta-circularity) -# This method will be replaces in the -# boostrap section of Class::MOP, by -# a new version which uses the +# This method will be replaced in the +# boostrap section of Class::MOP, by +# a new version which uses the # &Class::MOP::Class::construct_instance # method to build an attribute meta-object # which itself is described with attribute -# meta-objects. +# meta-objects. # - Ain't meta-circularity grand? :) sub new { my $class = shift; my $name = shift; - my %options = @_; - + my %options = @_; + (defined $name && $name) || confess "You must provide a name for the attribute"; - $options{init_arg} = $name + + $options{init_arg} = $name if not exists $options{init_arg}; - + if(exists $options{builder}){ + confess("builder must be a defined scalar value which is a method name") + if ref $options{builder} || !(defined $options{builder}); + confess("Setting both default and builder is not allowed.") + if exists $options{default}; + } else { + (is_default_a_coderef(\%options)) + || confess("References are not allowed as default values, you must ". + "wrap then in a CODE reference (ex: sub { [] } and not [])") + if exists $options{default} && ref $options{default}; + } + if( $options{required} and not( defined($options{builder}) || defined($options{init_arg}) || exists $options{default} ) ) { + confess("A required attribute must have either 'init_arg', 'builder', or 'default'"); + } bless { - name => $name, - accessor => $options{accessor}, - reader => $options{reader}, - writer => $options{writer}, - predicate => $options{predicate}, - init_arg => $options{init_arg}, - default => $options{default}, - # keep a weakened link to the + '$!name' => $name, + '$!accessor' => $options{accessor}, + '$!reader' => $options{reader}, + '$!writer' => $options{writer}, + '$!predicate' => $options{predicate}, + '$!clearer' => $options{clearer}, + '$!builder' => $options{builder}, + '$!init_arg' => $options{init_arg}, + '$!default' => $options{default}, + '$!initializer' => $options{initializer}, + # keep a weakened link to the # class we are associated with - associated_class => undef, + '$!associated_class' => undef, + # and a list of the methods + # associated with this attr + '@!associated_methods' => [], + # NOTE: + # protect this from silliness + init_arg => '!............( DO NOT DO THIS )............!', } => $class; } # NOTE: -# this is a primative (and kludgy) clone operation -# for now, it will be repleace in the Class::MOP -# bootstrap with a proper one, however we know +# this is a primative (and kludgy) clone operation +# for now, it will be replaced in the Class::MOP +# bootstrap with a proper one, however we know # that this one will work fine for now. sub clone { my $self = shift; @@ -61,135 +89,268 @@ sub clone { } sub initialize_instance_slot { - my ($self, $class, $instance, $params) = @_; - my $init_arg = $self->{init_arg}; + my ($self, $meta_instance, $instance, $params) = @_; + my $init_arg = $self->{'$!init_arg'}; # try to fetch the init arg from the %params ... - my $val; - $val = $params->{$init_arg} if exists $params->{$init_arg}; - # if nothing was in the %params, we can use the + + # if nothing was in the %params, we can use the # attribute's default value (if it has one) - if (!defined $val && defined $self->{default}) { - $val = $self->default($instance); - } - $instance->{$self->name} = $val; + if(defined $init_arg and exists $params->{$init_arg}){ + $self->_set_initial_slot_value( + $meta_instance, + $instance, + $params->{$init_arg}, + ); + } + elsif (defined $self->{'$!default'}) { + $self->_set_initial_slot_value( + $meta_instance, + $instance, + $self->default($instance), + ); + } + elsif (defined( my $builder = $self->{'$!builder'})) { + if ($builder = $instance->can($builder)) { + $self->_set_initial_slot_value( + $meta_instance, + $instance, + $instance->$builder, + ); + } + else { + confess(blessed($instance)." does not support builder method '". $self->{'$!builder'} ."' for attribute '" . $self->name . "'"); + } + } } -# NOTE: -# the next bunch of methods will get bootstrapped -# away in the Class::MOP bootstrapping section +sub _set_initial_slot_value { + my ($self, $meta_instance, $instance, $value) = @_; + + my $slot_name = $self->name; -sub name { $_[0]->{name} } + return $meta_instance->set_slot_value($instance, $slot_name, $value) + unless $self->has_initializer; -sub associated_class { $_[0]->{associated_class} } + my $callback = sub { + $meta_instance->set_slot_value($instance, $slot_name, $_[0]); + }; + + my $initializer = $self->initializer; + + # most things will just want to set a value, so make it first arg + $instance->$initializer($value, $callback, $self); +} -sub has_accessor { defined($_[0]->{accessor}) ? 1 : 0 } -sub has_reader { defined($_[0]->{reader}) ? 1 : 0 } -sub has_writer { defined($_[0]->{writer}) ? 1 : 0 } -sub has_predicate { defined($_[0]->{predicate}) ? 1 : 0 } -sub has_init_arg { defined($_[0]->{init_arg}) ? 1 : 0 } -sub has_default { defined($_[0]->{default}) ? 1 : 0 } +# NOTE: +# the next bunch of methods will get bootstrapped +# away in the Class::MOP bootstrapping section -sub accessor { $_[0]->{accessor} } -sub reader { $_[0]->{reader} } -sub writer { $_[0]->{writer} } -sub predicate { $_[0]->{predicate} } -sub init_arg { $_[0]->{init_arg} } +sub name { $_[0]->{'$!name'} } + +sub associated_class { $_[0]->{'$!associated_class'} } +sub associated_methods { $_[0]->{'@!associated_methods'} } + +sub has_accessor { defined($_[0]->{'$!accessor'}) ? 1 : 0 } +sub has_reader { defined($_[0]->{'$!reader'}) ? 1 : 0 } +sub has_writer { defined($_[0]->{'$!writer'}) ? 1 : 0 } +sub has_predicate { defined($_[0]->{'$!predicate'}) ? 1 : 0 } +sub has_clearer { defined($_[0]->{'$!clearer'}) ? 1 : 0 } +sub has_builder { defined($_[0]->{'$!builder'}) ? 1 : 0 } +sub has_init_arg { defined($_[0]->{'$!init_arg'}) ? 1 : 0 } +sub has_default { defined($_[0]->{'$!default'}) ? 1 : 0 } +sub has_initializer { defined($_[0]->{'$!initializer'}) ? 1 : 0 } + +sub accessor { $_[0]->{'$!accessor'} } +sub reader { $_[0]->{'$!reader'} } +sub writer { $_[0]->{'$!writer'} } +sub predicate { $_[0]->{'$!predicate'} } +sub clearer { $_[0]->{'$!clearer'} } +sub builder { $_[0]->{'$!builder'} } +sub init_arg { $_[0]->{'$!init_arg'} } +sub initializer { $_[0]->{'$!initializer'} } # end bootstrapped away method section. # (all methods below here are kept intact) -sub default { +sub get_read_method { + my $self = shift; + my $reader = $self->reader || $self->accessor; + # normal case ... + return $reader unless ref $reader; + # the HASH ref case + my ($name) = %$reader; + return $name; +} + +sub get_write_method { + my $self = shift; + my $writer = $self->writer || $self->accessor; + # normal case ... + return $writer unless ref $writer; + # the HASH ref case + my ($name) = %$writer; + return $name; +} + +sub get_read_method_ref { my $self = shift; - if (reftype($self->{default}) && reftype($self->{default}) eq 'CODE') { - # if the default is a CODE ref, then + if ((my $reader = $self->get_read_method) && $self->associated_class) { + return $self->associated_class->get_method($reader); + } + else { + return sub { $self->get_value(@_) }; + } +} + +sub get_write_method_ref { + my $self = shift; + if ((my $writer = $self->get_write_method) && $self->associated_class) { + return $self->associated_class->get_method($writer); + } + else { + return sub { $self->set_value(@_) }; + } +} + +sub is_default_a_coderef { + ('CODE' eq (reftype($_[0]->{'$!default'} || $_[0]->{default}) || '')) +} + +sub default { + my ($self, $instance) = @_; + if (defined $instance && $self->is_default_a_coderef) { + # if the default is a CODE ref, then # we pass in the instance and default - # can return a value based on that + # can return a value based on that # instance. Somewhat crude, but works. - return $self->{default}->(shift); - } - $self->{default}; + return $self->{'$!default'}->($instance); + } + $self->{'$!default'}; } -# class association +# slots + +sub slots { (shift)->name } + +# class association sub attach_to_class { my ($self, $class) = @_; (blessed($class) && $class->isa('Class::MOP::Class')) || confess "You must pass a Class::MOP::Class instance (or a subclass)"; - weaken($self->{associated_class} = $class); + weaken($self->{'$!associated_class'} = $class); } sub detach_from_class { my $self = shift; - $self->{associated_class} = undef; + $self->{'$!associated_class'} = undef; } -## Method generation helpers +# method association -sub generate_accessor_method { - my ($self, $attr_name) = @_; - sub { - $_[0]->{$attr_name} = $_[1] if scalar(@_) == 2; - $_[0]->{$attr_name}; - }; +sub associate_method { + my ($self, $method) = @_; + push @{$self->{'@!associated_methods'}} => $method; } -sub generate_reader_method { - my ($self, $attr_name) = @_; - sub { - confess "Cannot assign a value to a read-only accessor" if @_ > 1; - $_[0]->{$attr_name}; - }; +## Slot management + +sub set_initial_value { + my ($self, $instance, $value) = @_; + $self->set_initial_slot_value( + Class::MOP::Class->initialize(blessed($instance))->get_meta_instance, + $instance, + $value + ); } -sub generate_writer_method { - my ($self, $attr_name) = @_; - sub { $_[0]->{$attr_name} = $_[1] }; +sub set_value { + my ($self, $instance, $value) = @_; + + Class::MOP::Class->initialize(blessed($instance)) + ->get_meta_instance + ->set_slot_value($instance, $self->name, $value); } -sub generate_predicate_method { - my ($self, $attr_name) = @_; - sub { defined $_[0]->{$attr_name} ? 1 : 0 }; +sub get_value { + my ($self, $instance) = @_; + + Class::MOP::Class->initialize(blessed($instance)) + ->get_meta_instance + ->get_slot_value($instance, $self->name); } +sub has_value { + my ($self, $instance) = @_; + + Class::MOP::Class->initialize(blessed($instance)) + ->get_meta_instance + ->is_slot_initialized($instance, $self->name); +} + +sub clear_value { + my ($self, $instance) = @_; + + Class::MOP::Class->initialize(blessed($instance)) + ->get_meta_instance + ->deinitialize_slot($instance, $self->name); +} + +## load em up ... + +sub accessor_metaclass { 'Class::MOP::Method::Accessor' } + sub process_accessors { - my ($self, $type, $accessor) = @_; + my ($self, $type, $accessor, $generate_as_inline_methods) = @_; if (reftype($accessor)) { (reftype($accessor) eq 'HASH') - || confess "bad accessor/reader/writer/predicate format, must be a HASH ref"; - my ($name, $method) = each %{$accessor}; - return ($name, Class::MOP::Attribute::Accessor->wrap($method)); + || confess "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref"; + my ($name, $method) = %{$accessor}; + $method = $self->accessor_metaclass->wrap($method); + $self->associate_method($method); + return ($name, $method); } else { - my $generator = $self->can('generate_' . $type . '_method'); - ($generator) - || confess "There is no method generator for the type='$type'"; - if (my $method = $self->$generator($self->name)) { - return ($accessor => Class::MOP::Attribute::Accessor->wrap($method)); - } - confess "Could not create the '$type' method for " . $self->name . " because : $@"; - } + my $inline_me = ($generate_as_inline_methods && $self->associated_class->instance_metaclass->is_inlinable); + my $method; + eval { + $method = $self->accessor_metaclass->new( + attribute => $self, + is_inline => $inline_me, + accessor_type => $type, + ); + }; + confess "Could not create the '$type' method for " . $self->name . " because : $@" if $@; + $self->associate_method($method); + return ($accessor, $method); + } } sub install_accessors { - my $self = shift; - my $class = $self->associated_class; - + my $self = shift; + my $inline = shift; + my $class = $self->associated_class; + $class->add_method( - $self->process_accessors('accessor' => $self->accessor()) + $self->process_accessors('accessor' => $self->accessor(), $inline) ) if $self->has_accessor(); - $class->add_method( - $self->process_accessors('reader' => $self->reader()) + $class->add_method( + $self->process_accessors('reader' => $self->reader(), $inline) ) if $self->has_reader(); $class->add_method( - $self->process_accessors('writer' => $self->writer()) + $self->process_accessors('writer' => $self->writer(), $inline) ) if $self->has_writer(); $class->add_method( - $self->process_accessors('predicate' => $self->predicate()) + $self->process_accessors('predicate' => $self->predicate(), $inline) ) if $self->has_predicate(); + + $class->add_method( + $self->process_accessors('clearer' => $self->clearer(), $inline) + ) if $self->has_clearer(); + return; } @@ -198,57 +359,52 @@ sub install_accessors { my ($accessor, $class) = @_; if (reftype($accessor) && reftype($accessor) eq 'HASH') { ($accessor) = keys %{$accessor}; - } - my $method = $class->get_method($accessor); - $class->remove_method($accessor) - if (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor')); + } + my $method = $class->get_method($accessor); + $class->remove_method($accessor) + if (blessed($method) && $method->isa('Class::MOP::Method::Accessor')); }; - + sub remove_accessors { my $self = shift; + # TODO: + # we really need to make sure to remove from the + # associates methods here as well. But this is + # such a slimly used method, I am not worried + # about it right now. $_remove_accessor->($self->accessor(), $self->associated_class()) if $self->has_accessor(); $_remove_accessor->($self->reader(), $self->associated_class()) if $self->has_reader(); $_remove_accessor->($self->writer(), $self->associated_class()) if $self->has_writer(); $_remove_accessor->($self->predicate(), $self->associated_class()) if $self->has_predicate(); - return; + $_remove_accessor->($self->clearer(), $self->associated_class()) if $self->has_clearer(); + return; } } -package Class::MOP::Attribute::Accessor; - -use strict; -use warnings; - -use Class::MOP::Method; - -our $VERSION = '0.01'; - -our @ISA = ('Class::MOP::Method'); - 1; __END__ =pod -=head1 NAME +=head1 NAME 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 + 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 + 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 )); @@ -256,13 +412,13 @@ Class::MOP::Attribute - Attribute Meta Object =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 +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 +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. =head1 METHODS @@ -273,7 +429,7 @@ object attributes. =item B -An attribute must (at the very least), have a C<$name>. All other +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: @@ -281,109 +437,130 @@ are as follows: =item I -This should be a string value representing the expected key in -an initialization hash. For instance, if we have an 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. MyClass->meta->construct_instance(-foo => "Hello There"); -In an init_arg is not assigned, it will automatically use the +In an init_arg is not assigned, it will automatically use the value of C<$name>. +=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. + =item I -The value of this key is the default value which -C will initialize the -attribute to. +The value of this key is the default value which +C will initialize the +attribute to. 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 +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 ... - + + # or ... + Class::MOP::Attribute->new('%foo' => ( default => sub { {} }, - )); + )); -If you wish to initialize an attribute with a CODE reference +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 raw (unblessed) instance structure +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 raw (unblessed) 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 +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 :). =back -The 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 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. =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, +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. B -This method will properly handle the following code, by assigning an +This method will properly handle the following code, by assigning an C value to the attribute. $object->set_something(undef); =item I -This is a basic read-only accessor, it will just return the value of +This is a basic read-only accessor, it will just return 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. +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. B -This method will properly handle the following code, by assigning an +This method will properly handle the following code, by assigning an C value to the attribute. $object->set_something(); =item I -This is a basic test to see if the value of the attribute is not -C. It will return true (C<1>) if the attribute's value is -defined, and false (C<0>) otherwise. +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. + +If you really want to get rid of the value, you have to define and +use a I (see below). + + +=item I + +This is the a method that will uninitialize the attr, reverting lazy values +back to their "unfulfilled" state. =back @@ -391,11 +568,49 @@ defined, and false (C<0>) otherwise. =item B -=back +=back + +=head2 Value management + +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. + +=over 4 + +=item B + +Set the value without going through the accessor. Note that this may be done to +even attributes with just read only accessors. + +=item B + +This method sets the value without going through the accessor -- but it is only +called when the instance data is first initialized. + +=item B + +Return the value without going through the accessor. Note that this may be done +even to attributes with just write only accessors. + +=item B + +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 + +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. + +=back =head2 Informational -These are all basic read-only value accessors for the values +These are all basic read-only value accessors for the values passed into C. I think they are pretty much self-explanitory. =over 4 @@ -410,13 +625,45 @@ passed into C. I think they are pretty much self-explanitory. =item B +=item B + +=item B + =item B +=item B + =item B -As noted in the documentation for C above, if the I -value is a CODE reference, this accessor will pass a single additional -argument C<$instance> into it and return the value. +Return the default value for the attribute. + +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. + +=item B + +Return a list of slots required by the attribute. This is usually +just one, which is the name of the attribute. + +=item B + +=item B + +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 + +=item B + +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. + +NOTE: If not reader/writer/accessor was specified, this will use the +attribute get_value/set_value methods, which can be very inefficient. =back @@ -434,63 +681,94 @@ These are all basic predicate methods for the values passed into C. =item B +=item B + +=item B + =item B =item B +=item B + =back =head2 Class association +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. + =over 4 =item B +This returns the metaclass this attribute is associated with. + =item B +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. + =item B +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. + =back =head2 Attribute Accessor generation =over 4 -=item B +=item B -This allows the attribute to generate and install code for it's own -I methods. This is called by -C. +Accessors are generated by an accessor metaclass, which is usually +a subclass of C. This method returns +the name of the accessor metaclass that this attribute uses. -This method will call C for each of the possible -method types (accessor, reader, writer & predicate). +=item B -=item B +This will associate a C<$method> with the given attribute which is +used internally by the accessor generator. -This 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. +=item B -=over 4 +This will return the list of methods which have been associated with +the C methods. -=item B +=item B -=item B +This allows the attribute to generate and install code for it's own +I methods. This is called by +C. -=item B +This method will call C for each of the possible +method types (accessor, reader, writer & predicate). -=item B +=item B -=back +This 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. =item B -This allows the attribute to remove the method for it's own -I. This is called by +This allows the attribute to remove the method for it's own +I. This is called by C. +NOTE: This does not currently remove methods from the list returned +by C, that is on the TODO list. + =back =head2 Introspection @@ -499,27 +777,29 @@ C. =item B -This will return a B instance which is related +This will return a B instance which is related to 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 benifits -of the MOP when subclassing it. +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 benifits +of the MOP when subclassing it. =back -=head1 AUTHOR +=head1 AUTHORS Stevan Little Estevan@iinteractive.comE =head1 COPYRIGHT AND LICENSE -Copyright 2006 by Infinity Interactive, Inc. +Copyright 2006-2008 by Infinity Interactive, Inc. L This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. +it under the same terms as Perl itself. + +=cut + -=cut \ No newline at end of file