Fix a typo in the changes.
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
CommitLineData
c0e30cf5 1
2package Moose::Meta::Attribute;
3
4use strict;
5use warnings;
6
78cd1d3b 7use Scalar::Util 'blessed', 'weaken', 'reftype';
a15dff8d 8use Carp 'confess';
a909a4df 9use overload ();
a15dff8d 10
26fbace8 11our $VERSION = '0.13';
d44714be 12our $AUTHORITY = 'cpan:STEVAN';
78cd1d3b 13
8ee73eeb 14use Moose::Meta::Method::Accessor;
a3c7e2fe 15use Moose::Util::TypeConstraints ();
bc1e29b5 16
c0e30cf5 17use base 'Class::MOP::Attribute';
18
452bac1b 19# options which are not directly used
20# but we store them for metadata purposes
98aae381 21__PACKAGE__->meta->add_attribute('isa' => (reader => '_isa_metadata'));
22__PACKAGE__->meta->add_attribute('does' => (reader => '_does_metadata'));
23__PACKAGE__->meta->add_attribute('is' => (reader => '_is_metadata'));
452bac1b 24
25# these are actual options for the attrs
1a563243 26__PACKAGE__->meta->add_attribute('required' => (reader => 'is_required' ));
27__PACKAGE__->meta->add_attribute('lazy' => (reader => 'is_lazy' ));
26fbace8 28__PACKAGE__->meta->add_attribute('lazy_build' => (reader => 'is_lazy_build' ));
1a563243 29__PACKAGE__->meta->add_attribute('coerce' => (reader => 'should_coerce' ));
30__PACKAGE__->meta->add_attribute('weak_ref' => (reader => 'is_weak_ref' ));
31__PACKAGE__->meta->add_attribute('auto_deref' => (reader => 'should_auto_deref'));
82168dbb 32__PACKAGE__->meta->add_attribute('type_constraint' => (
33 reader => 'type_constraint',
34 predicate => 'has_type_constraint',
35));
8c9d74e7 36__PACKAGE__->meta->add_attribute('trigger' => (
37 reader => 'trigger',
38 predicate => 'has_trigger',
39));
452bac1b 40__PACKAGE__->meta->add_attribute('handles' => (
41 reader => 'handles',
42 predicate => 'has_handles',
43));
ddbdc0cb 44__PACKAGE__->meta->add_attribute('documentation' => (
45 reader => 'documentation',
46 predicate => 'has_documentation',
47));
82168dbb 48
78cd1d3b 49sub new {
26fbace8 50 my ($class, $name, %options) = @_;
51 $class->_process_options($name, \%options);
52 return $class->SUPER::new($name, %options);
1d768fb1 53}
54
ce0e8d63 55sub clone_and_inherit_options {
56 my ($self, %options) = @_;
83cc9094 57 # you can change default, required, coerce, documentation and lazy
ce0e8d63 58 my %actual_options;
83cc9094 59 foreach my $legal_option (qw(default coerce required documentation lazy)) {
ce0e8d63 60 if (exists $options{$legal_option}) {
61 $actual_options{$legal_option} = $options{$legal_option};
62 delete $options{$legal_option};
63 }
64 }
26fbace8 65
83cc9094 66 # handles can only be added, not changed
67 if ($options{handles}) {
68 confess "You can only add the 'handles' option, you cannot change it"
69 if $self->has_handles;
70 $actual_options{handles} = $options{handles};
71 delete $options{handles};
72 }
26fbace8 73
74 # isa can be changed, but only if the
75 # new type is a subtype
ce0e8d63 76 if ($options{isa}) {
77 my $type_constraint;
26fbace8 78 if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
79 $type_constraint = $options{isa};
80 }
81 else {
82 $type_constraint = Moose::Util::TypeConstraints::find_type_constraint($options{isa});
83 (defined $type_constraint)
84 || confess "Could not find the type constraint '" . $options{isa} . "'";
85 }
86 # NOTE:
87 # check here to see if the new type
88 # is a subtype of the old one
89 ($type_constraint->is_subtype_of($self->type_constraint->name))
90 || confess "New type constraint setting must be a subtype of inherited one"
91 # iff we have a type constraint that is ...
92 if $self->has_type_constraint;
93 # then we use it :)
94 $actual_options{type_constraint} = $type_constraint;
ce0e8d63 95 delete $options{isa};
96 }
26fbace8 97 (scalar keys %options == 0)
ce0e8d63 98 || confess "Illegal inherited options => (" . (join ', ' => keys %options) . ")";
99 $self->clone(%actual_options);
1d768fb1 100}
101
102sub _process_options {
103 my ($class, $name, $options) = @_;
26fbace8 104
105 if (exists $options->{is}) {
106 if ($options->{is} eq 'ro') {
107 $options->{reader} ||= $name;
108 (!exists $options->{trigger})
109 || confess "Cannot have a trigger on a read-only attribute";
110 }
111 elsif ($options->{is} eq 'rw') {
112 $options->{accessor} = $name;
113 ((reftype($options->{trigger}) || '') eq 'CODE')
114 || confess "Trigger must be a CODE ref"
115 if exists $options->{trigger};
116 }
117 else {
118 confess "I do not understand this option (is => " . $options->{is} . ")"
119 }
120 }
121
122 if (exists $options->{isa}) {
123
124 if (exists $options->{does}) {
125 if (eval { $options->{isa}->can('does') }) {
126 ($options->{isa}->does($options->{does}))
127 || confess "Cannot have an isa option and a does option if the isa does not do the does";
128 }
129 else {
130 confess "Cannot have an isa option which cannot ->does()";
131 }
132 }
133
134 # allow for anon-subtypes here ...
135 if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
136 $options->{type_constraint} = $options->{isa};
137 }
138 else {
139 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_type_constraint(
140 $options->{isa} => {
141 parent => Moose::Util::TypeConstraints::find_type_constraint('Object'),
142 constraint => sub { $_[0]->isa($options->{isa}) }
143 }
144 );
145 }
146 }
147 elsif (exists $options->{does}) {
148 # allow for anon-subtypes here ...
149 if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
150 $options->{type_constraint} = $options->{isa};
151 }
152 else {
153 $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_type_constraint(
154 $options->{does} => {
155 parent => Moose::Util::TypeConstraints::find_type_constraint('Role'),
156 constraint => sub { $_[0]->does($options->{does}) }
157 }
158 );
159 }
160 }
161
162 if (exists $options->{coerce} && $options->{coerce}) {
163 (exists $options->{type_constraint})
164 || confess "You cannot have coercion without specifying a type constraint";
4b598ea3 165 confess "You cannot have a weak reference to a coerced value"
26fbace8 166 if $options->{weak_ref};
167 }
168
169 if (exists $options->{auto_deref} && $options->{auto_deref}) {
170 (exists $options->{type_constraint})
171 || confess "You cannot auto-dereference without specifying a type constraint";
172 ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
94b8bbb8 173 $options->{type_constraint}->is_a_type_of('HashRef'))
26fbace8 174 || confess "You cannot auto-dereference anything other than a ArrayRef or HashRef";
175 }
176
177 if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
178 confess("You can not use lazy_build and default for the same attribute")
179 if exists $options->{default};
180 $options->{lazy} = 1;
181 $options->{required} = 1;
182 if($name =~ /^_/){
183 $options->{builder} ||= "_build${name}";
184 $options->{clearer} ||= "_clear${name}";
185 $options->{predicate} ||= "_has${name}";
186 } else {
187 $options->{builder} ||= "build_${name}";
188 $options->{clearer} ||= "clear_${name}";
189 $options->{predicate} ||= "has_${name}";
190 }
191 }
192
193 if (exists $options->{lazy} && $options->{lazy}) {
194 (exists $options->{default} || exists $options->{builder} )
195 || confess "You cannot have lazy attribute without specifying a default value for it";
196 }
197
78cd1d3b 198}
c0e30cf5 199
d500266f 200sub initialize_instance_slot {
ddd0ec20 201 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 202 my $init_arg = $self->init_arg();
203 # try to fetch the init arg from the %params ...
ddd0ec20 204
26fbace8 205 my $val;
d500266f 206 if (exists $params->{$init_arg}) {
207 $val = $params->{$init_arg};
26fbace8 208
ab859145 209 if (!defined $val && $self->is_required) {
26fbace8 210 confess "Attribute (" . $self->name . ") is required and cannot be undef";
ab859145 211 }
d500266f 212 }
213 else {
214 # skip it if it's lazy
215 return if $self->is_lazy;
216 # and die if it's required and doesn't have a default value
26fbace8 217 confess "Attribute (" . $self->name . ") is required"
218 if $self->is_required && !$self->has_default && !$self->has_builder;
d500266f 219 }
ddd0ec20 220
26fbace8 221 # if nothing was in the %params, we can use the
d500266f 222 # attribute's default value (if it has one)
223 if (!defined $val && $self->has_default) {
26fbace8 224 $val = $self->default($instance);
225 } elsif (!defined $val && $self->has_builder) {
226 my $builder = $self->builder;
227 confess(blessed($instance)." does not support builder method '$builder' for attribute '" . $self->name . "'")
228 unless $instance->can($builder);
229 $val = $instance->$builder;
230 }
231
232 if (defined $val || $self->has_default) {
233 if ($self->has_type_constraint) {
234 my $type_constraint = $self->type_constraint;
235 if ($self->should_coerce && $type_constraint->has_coercion) {
236 $val = $type_constraint->coerce($val);
237 }
238 (defined($type_constraint->check($val)))
239 || confess "Attribute (" .
240 $self->name .
241 ") does not pass the type constraint (" .
c07af9d2 242 $type_constraint->name .
26fbace8 243 ") with '" .
244 (defined $val
245 ? (blessed($val) && overload::Overloaded($val)
246 ? overload::StrVal($val)
247 : $val)
248 : 'undef') .
249 "'";
250 }
d500266f 251 }
ddd0ec20 252
ac1ef2f9 253 $meta_instance->set_slot_value($instance, $self->name, $val);
26fbace8 254 $meta_instance->weaken_slot_value($instance, $self->name)
ac1ef2f9 255 if ref $val && $self->is_weak_ref;
d500266f 256}
257
d617b644 258## Slot management
9e93dd19 259
946289d1 260sub set_value {
261 my ($self, $instance, $value) = @_;
26fbace8 262
946289d1 263 my $attr_name = $self->name;
26fbace8 264
946289d1 265 if ($self->is_required) {
26fbace8 266 defined($value)
946289d1 267 || confess "Attribute ($attr_name) is required, so cannot be set to undef";
268 }
26fbace8 269
946289d1 270 if ($self->has_type_constraint) {
26fbace8 271
946289d1 272 my $type_constraint = $self->type_constraint;
26fbace8 273
946289d1 274 if ($self->should_coerce) {
26fbace8 275 $value = $type_constraint->coerce($value);
946289d1 276 }
277 defined($type_constraint->_compiled_type_constraint->($value))
26fbace8 278 || confess "Attribute ($attr_name) does not pass the type constraint ("
279 . $type_constraint->name
280 . ") with "
281 . (defined($value)
282 ? ("'" .
283 (blessed($value) && overload::Overloaded($value)
284 ? overload::StrVal($value)
285 : $value)
286 . "'")
a909a4df 287 : "undef")
946289d1 288 if defined($value);
289 }
26fbace8 290
946289d1 291 my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
292 ->get_meta_instance;
26fbace8 293
294 $meta_instance->set_slot_value($instance, $attr_name, $value);
295
946289d1 296 if (ref $value && $self->is_weak_ref) {
26fbace8 297 $meta_instance->weaken_slot_value($instance, $attr_name);
946289d1 298 }
26fbace8 299
946289d1 300 if ($self->has_trigger) {
301 $self->trigger->($instance, $value, $self);
302 }
303}
304
305sub get_value {
306 my ($self, $instance) = @_;
26fbace8 307
946289d1 308 if ($self->is_lazy) {
26fbace8 309 unless ($self->has_value($instance)) {
310 if ($self->has_default) {
311 my $default = $self->default($instance);
312 $self->set_value($instance, $default);
313 }
314 if ( $self->has_builder ){
315 my $builder = $self->builder;
316 confess(blessed($instance)." does not support builder method '$builder' for attribute '" . $self->name . "'")
317 unless $instance->can($builder);
318 $self->set_value($instance, $instance->$builder);
319 } else {
320 $self->set_value($instance, undef);
321 }
322 }
946289d1 323 }
26fbace8 324
946289d1 325 if ($self->should_auto_deref) {
26fbace8 326
946289d1 327 my $type_constraint = $self->type_constraint;
328
329 if ($type_constraint->is_a_type_of('ArrayRef')) {
330 my $rv = $self->SUPER::get_value($instance);
331 return unless defined $rv;
332 return wantarray ? @{ $rv } : $rv;
26fbace8 333 }
946289d1 334 elsif ($type_constraint->is_a_type_of('HashRef')) {
335 my $rv = $self->SUPER::get_value($instance);
336 return unless defined $rv;
337 return wantarray ? %{ $rv } : $rv;
26fbace8 338 }
946289d1 339 else {
340 confess "Can not auto de-reference the type constraint '" . $type_constraint->name . "'";
341 }
26fbace8 342
946289d1 343 }
344 else {
26fbace8 345
946289d1 346 return $self->SUPER::get_value($instance);
26fbace8 347 }
946289d1 348}
a15dff8d 349
26fbace8 350## installing accessors
c0e30cf5 351
d617b644 352sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
d7f17ebb 353
452bac1b 354sub install_accessors {
355 my $self = shift;
26fbace8 356 $self->SUPER::install_accessors(@_);
357
452bac1b 358 if ($self->has_handles) {
26fbace8 359
452bac1b 360 # NOTE:
361 # Here we canonicalize the 'handles' option
26fbace8 362 # this will sort out any details and always
363 # return an hash of methods which we want
452bac1b 364 # to delagate to, see that method for details
365 my %handles = $self->_canonicalize_handles();
26fbace8 366
452bac1b 367 # find the name of the accessor for this attribute
368 my $accessor_name = $self->reader || $self->accessor;
369 (defined $accessor_name)
370 || confess "You cannot install delegation without a reader or accessor for the attribute";
26fbace8 371
452bac1b 372 # make sure we handle HASH accessors correctly
373 ($accessor_name) = keys %{$accessor_name}
374 if ref($accessor_name) eq 'HASH';
26fbace8 375
452bac1b 376 # install the delegation ...
377 my $associated_class = $self->associated_class;
378 foreach my $handle (keys %handles) {
379 my $method_to_call = $handles{$handle};
26fbace8 380
452bac1b 381 (!$associated_class->has_method($handle))
382 || confess "You cannot overwrite a locally defined method ($handle) with a delegation";
26fbace8 383
d022f632 384 # NOTE:
385 # handles is not allowed to delegate
26fbace8 386 # any of these methods, as they will
387 # override the ones in your class, which
d022f632 388 # is almost certainly not what you want.
389 next if $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 390
452bac1b 391 if ((reftype($method_to_call) || '') eq 'CODE') {
26fbace8 392 $associated_class->add_method($handle => $method_to_call);
452bac1b 393 }
394 else {
395 $associated_class->add_method($handle => sub {
b805c70c 396 # FIXME
26fbace8 397 # we should check for lack of
398 # a callable return value from
399 # the accessor here
cbe25729 400 my $proxy = (shift)->$accessor_name();
401 @_ = ($proxy, @_);
402 goto &{ $proxy->can($method_to_call)};
452bac1b 403 });
404 }
405 }
406 }
26fbace8 407
452bac1b 408 return;
409}
410
98aae381 411# private methods to help delegation ...
412
452bac1b 413sub _canonicalize_handles {
414 my $self = shift;
415 my $handles = $self->handles;
c84f324f 416 if (my $handle_type = ref($handles)) {
417 if ($handle_type eq 'HASH') {
418 return %{$handles};
419 }
420 elsif ($handle_type eq 'ARRAY') {
421 return map { $_ => $_ } @{$handles};
422 }
423 elsif ($handle_type eq 'Regexp') {
424 ($self->has_type_constraint)
425 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
26fbace8 426 return map { ($_ => $_) }
c84f324f 427 grep { /$handles/ } $self->_get_delegate_method_list;
428 }
429 elsif ($handle_type eq 'CODE') {
430 return $handles->($self, $self->_find_delegate_metaclass);
431 }
432 else {
433 confess "Unable to canonicalize the 'handles' option with $handles";
434 }
452bac1b 435 }
436 else {
c84f324f 437 my $role_meta = eval { $handles->meta };
438 if ($@) {
26fbace8 439 confess "Unable to canonicalize the 'handles' option with $handles because : $@";
c84f324f 440 }
441
442 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
443 || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
26fbace8 444
c84f324f 445 return map { $_ => $_ } (
26fbace8 446 $role_meta->get_method_list,
c84f324f 447 $role_meta->get_required_method_list
448 );
452bac1b 449 }
450}
451
452sub _find_delegate_metaclass {
453 my $self = shift;
98aae381 454 if (my $class = $self->_isa_metadata) {
26fbace8 455 # if the class does have
452bac1b 456 # a meta method, use it
457 return $class->meta if $class->can('meta');
26fbace8 458 # otherwise we might be
452bac1b 459 # dealing with a non-Moose
26fbace8 460 # class, and need to make
452bac1b 461 # our own metaclass
462 return Moose::Meta::Class->initialize($class);
463 }
98aae381 464 elsif (my $role = $self->_does_metadata) {
26fbace8 465 # our role will always have
452bac1b 466 # a meta method
98aae381 467 return $role->meta;
452bac1b 468 }
469 else {
470 confess "Cannot find delegate metaclass for attribute " . $self->name;
471 }
472}
473
474sub _get_delegate_method_list {
475 my $self = shift;
476 my $meta = $self->_find_delegate_metaclass;
477 if ($meta->isa('Class::MOP::Class')) {
093b12c2 478 return map { $_->{name} } # NOTE: !never! delegate &meta
26fbace8 479 grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
452bac1b 480 $meta->compute_all_applicable_methods;
481 }
482 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 483 return $meta->get_method_list;
452bac1b 484 }
485 else {
486 confess "Unable to recognize the delegate metaclass '$meta'";
487 }
488}
489
c0e30cf5 4901;
491
492__END__
493
494=pod
495
496=head1 NAME
497
6ba6d68c 498Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 499
500=head1 DESCRIPTION
501
26fbace8 502This is a subclass of L<Class::MOP::Attribute> with Moose specific
503extensions.
6ba6d68c 504
26fbace8 505For the most part, the only time you will ever encounter an
506instance of this class is if you are doing some serious deep
507introspection. To really understand this class, you need to refer
6ba6d68c 508to the L<Class::MOP::Attribute> documentation.
e522431d 509
c0e30cf5 510=head1 METHODS
511
6ba6d68c 512=head2 Overridden methods
513
26fbace8 514These methods override methods in L<Class::MOP::Attribute> and add
515Moose specific features. You can safely assume though that they
6ba6d68c 516will behave just as L<Class::MOP::Attribute> does.
517
c0e30cf5 518=over 4
519
520=item B<new>
521
d500266f 522=item B<initialize_instance_slot>
523
452bac1b 524=item B<install_accessors>
525
39b3bc94 526=item B<accessor_metaclass>
527
946289d1 528=item B<get_value>
529
530=item B<set_value>
531
bcbaa845 532 eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
533 if($@) {
534 print "Oops: $@\n";
535 }
536
537I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
538
539Before setting the value, a check is made on the type constraint of
540the attribute, if it has one, to see if the value passes it. If the
541value fails to pass, the set operation dies with a L<Carp/confess>.
542
543Any coercion to convert values is done before checking the type constraint.
544
545To check a value against a type constraint before setting it, fetch the
546attribute instance using L<Moose::Meta::Attribute/find_attribute_by_name>,
547fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
548and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
549for an example.
550
a15dff8d 551=back
552
6ba6d68c 553=head2 Additional Moose features
554
26fbace8 555Moose attributes support type-constraint checking, weak reference
556creation and type coercion.
6ba6d68c 557
a15dff8d 558=over 4
559
9e93dd19 560=item B<clone_and_inherit_options>
561
26fbace8 562This is to support the C<has '+foo'> feature, it clones an attribute
563from a superclass and allows a very specific set of changes to be made
9e93dd19 564to the attribute.
565
a15dff8d 566=item B<has_type_constraint>
567
6ba6d68c 568Returns true if this meta-attribute has a type constraint.
569
a15dff8d 570=item B<type_constraint>
571
26fbace8 572A read-only accessor for this meta-attribute's type constraint. For
573more information on what you can do with this, see the documentation
6ba6d68c 574for L<Moose::Meta::TypeConstraint>.
a15dff8d 575
452bac1b 576=item B<has_handles>
577
578Returns true if this meta-attribute performs delegation.
579
580=item B<handles>
581
582This returns the value which was passed into the handles option.
583
6ba6d68c 584=item B<is_weak_ref>
a15dff8d 585
02a0fb52 586Returns true if this meta-attribute produces a weak reference.
4b598ea3 587
ca01a97b 588=item B<is_required>
589
02a0fb52 590Returns true if this meta-attribute is required to have a value.
ca01a97b 591
592=item B<is_lazy>
593
02a0fb52 594Returns true if this meta-attribute should be initialized lazily.
ca01a97b 595
26fbace8 596NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
597
598=item B<is_lazy_build>
599
600Returns true if this meta-attribute should be initialized lazily through
601the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
602make your attribute required and lazy. In addition it will set the builder, clearer
603and predicate options for you using the following convention.
604
605 #If your attribute name starts with an underscore:
606 has '_foo' => (lazy_build => 1);
607 #is the same as
608 has '_foo' => (lazy => 1, required => 1, builder => '_build_foo', predicate => '_has_foo', clearer => '_clear_foo');
609 # or
610 has '_foo' => (lazy => 1, required => 1, builder => '_build_foo', default => sub{shift->_build_foo}, clearer => '_clear_foo');
611
612 #If your attribute name does not start with an underscore:
613 has 'foo' => (lazy => 1, required => 1, builder => 'build_foo', predicate => 'has_foo', clearer => 'clear_foo');
614 # or
615 has '_foo' => (lazy => 1, required => 1, builder => '_build_foo', default => sub{shift->build_foo}, clearer => '_clear_foo');
616
617NOTE: This means your class should provide a method whose name matches the value
618of the builder part, in this case _build_foo or build_foo.
ca01a97b 619
34a66aa3 620=item B<should_coerce>
4b598ea3 621
02a0fb52 622Returns true if this meta-attribute should perform type coercion.
6ba6d68c 623
536f0b17 624=item B<should_auto_deref>
625
26fbace8 626Returns true if this meta-attribute should perform automatic
627auto-dereferencing.
536f0b17 628
26fbace8 629NOTE: This can only be done for attributes whose type constraint is
536f0b17 630either I<ArrayRef> or I<HashRef>.
631
8c9d74e7 632=item B<has_trigger>
633
02a0fb52 634Returns true if this meta-attribute has a trigger set.
635
8c9d74e7 636=item B<trigger>
637
26fbace8 638This is a CODE reference which will be executed every time the
639value of an attribute is assigned. The CODE ref will get two values,
640the invocant and the new value. This can be used to handle I<basic>
02a0fb52 641bi-directional relations.
642
ddbdc0cb 643=item B<documentation>
644
26fbace8 645This is a string which contains the documentation for this attribute.
ddbdc0cb 646It serves no direct purpose right now, but it might in the future
647in some kind of automated documentation system perhaps.
648
649=item B<has_documentation>
650
651Returns true if this meta-attribute has any documentation.
652
c0e30cf5 653=back
654
655=head1 BUGS
656
26fbace8 657All complex software has bugs lurking in it, and this module is no
c0e30cf5 658exception. If you find a bug please either email me, or add the bug
659to cpan-RT.
660
c0e30cf5 661=head1 AUTHOR
662
663Stevan Little E<lt>stevan@iinteractive.comE<gt>
664
98aae381 665Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
666
c0e30cf5 667=head1 COPYRIGHT AND LICENSE
668
b77fdbed 669Copyright 2006, 2007 by Infinity Interactive, Inc.
c0e30cf5 670
671L<http://www.iinteractive.com>
672
673This library is free software; you can redistribute it and/or modify
26fbace8 674it under the same terms as Perl itself.
c0e30cf5 675
8a7a9c53 676=cut