cleanup some stuff before release
[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
0b26305c 11our $VERSION = '0.14';
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;
58f85113 182 $options->{builder} ||= "_build_${name}";
26fbace8 183 if($name =~ /^_/){
26fbace8 184 $options->{clearer} ||= "_clear${name}";
185 $options->{predicate} ||= "_has${name}";
186 } else {
26fbace8 187 $options->{clearer} ||= "clear_${name}";
188 $options->{predicate} ||= "has_${name}";
189 }
190 }
191
192 if (exists $options->{lazy} && $options->{lazy}) {
193 (exists $options->{default} || exists $options->{builder} )
194 || confess "You cannot have lazy attribute without specifying a default value for it";
195 }
196
78cd1d3b 197}
c0e30cf5 198
d500266f 199sub initialize_instance_slot {
ddd0ec20 200 my ($self, $meta_instance, $instance, $params) = @_;
d500266f 201 my $init_arg = $self->init_arg();
202 # try to fetch the init arg from the %params ...
ddd0ec20 203
26fbace8 204 my $val;
1ed0b94f 205 my $value_is_set;
d500266f 206 if (exists $params->{$init_arg}) {
207 $val = $params->{$init_arg};
1ed0b94f 208 $value_is_set = 1;
d500266f 209 }
210 else {
211 # skip it if it's lazy
212 return if $self->is_lazy;
213 # and die if it's required and doesn't have a default value
26fbace8 214 confess "Attribute (" . $self->name . ") is required"
215 if $self->is_required && !$self->has_default && !$self->has_builder;
ddd0ec20 216
1ed0b94f 217 # if nothing was in the %params, we can use the
218 # attribute's default value (if it has one)
219 if ($self->has_default) {
220 $val = $self->default($instance);
221 $value_is_set = 1;
222 } elsif ($self->has_builder) {
0b26305c 223 if(my $builder = $instance->can($self->builder)){
1ed0b94f 224 $val = $instance->$builder;
225 $value_is_set = 1;
226 } else {
0b26305c 227 confess(blessed($instance)." does not support builder method '".$self->builder."' for attribute '" . $self->name . "'");
1ed0b94f 228 }
a0748c37 229 }
26fbace8 230 }
231
1ed0b94f 232 return unless $value_is_set;
233
234 if ($self->has_type_constraint) {
235 my $type_constraint = $self->type_constraint;
236 if ($self->should_coerce && $type_constraint->has_coercion) {
237 $val = $type_constraint->coerce($val);
d500266f 238 }
1ed0b94f 239 (defined($type_constraint->check($val)))
240 || confess "Attribute (" .
241 $self->name .
242 ") does not pass the type constraint (" .
243 $type_constraint->name .
244 ") with '" .
245 (defined $val
246 ? (blessed($val) && overload::Overloaded($val)
247 ? overload::StrVal($val)
248 : $val)
249 : 'undef') .
250 "'";
251 }
ddd0ec20 252
ac1ef2f9 253 $meta_instance->set_slot_value($instance, $self->name, $val);
26fbace8 254 $meta_instance->weaken_slot_value($instance, $self->name)
1ed0b94f 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 ){
0b26305c 315 if(my $builder = $instance->can($self->builder)){
a0748c37 316 $self->set_value($instance, $instance->$builder);
317 } else {
0b26305c 318 confess(blessed($instance)." does not support builder method '".$self->builder."' for attribute '" . $self->name . "'");
a0748c37 319 }
26fbace8 320 } else {
321 $self->set_value($instance, undef);
322 }
323 }
946289d1 324 }
26fbace8 325
946289d1 326 if ($self->should_auto_deref) {
26fbace8 327
946289d1 328 my $type_constraint = $self->type_constraint;
329
330 if ($type_constraint->is_a_type_of('ArrayRef')) {
331 my $rv = $self->SUPER::get_value($instance);
332 return unless defined $rv;
333 return wantarray ? @{ $rv } : $rv;
26fbace8 334 }
946289d1 335 elsif ($type_constraint->is_a_type_of('HashRef')) {
336 my $rv = $self->SUPER::get_value($instance);
337 return unless defined $rv;
338 return wantarray ? %{ $rv } : $rv;
26fbace8 339 }
946289d1 340 else {
341 confess "Can not auto de-reference the type constraint '" . $type_constraint->name . "'";
342 }
26fbace8 343
946289d1 344 }
345 else {
26fbace8 346
946289d1 347 return $self->SUPER::get_value($instance);
26fbace8 348 }
946289d1 349}
a15dff8d 350
26fbace8 351## installing accessors
c0e30cf5 352
d617b644 353sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
d7f17ebb 354
452bac1b 355sub install_accessors {
356 my $self = shift;
26fbace8 357 $self->SUPER::install_accessors(@_);
358
452bac1b 359 if ($self->has_handles) {
26fbace8 360
452bac1b 361 # NOTE:
362 # Here we canonicalize the 'handles' option
26fbace8 363 # this will sort out any details and always
364 # return an hash of methods which we want
452bac1b 365 # to delagate to, see that method for details
366 my %handles = $self->_canonicalize_handles();
26fbace8 367
452bac1b 368 # find the name of the accessor for this attribute
369 my $accessor_name = $self->reader || $self->accessor;
370 (defined $accessor_name)
371 || confess "You cannot install delegation without a reader or accessor for the attribute";
26fbace8 372
452bac1b 373 # make sure we handle HASH accessors correctly
374 ($accessor_name) = keys %{$accessor_name}
375 if ref($accessor_name) eq 'HASH';
26fbace8 376
452bac1b 377 # install the delegation ...
378 my $associated_class = $self->associated_class;
379 foreach my $handle (keys %handles) {
380 my $method_to_call = $handles{$handle};
26fbace8 381
452bac1b 382 (!$associated_class->has_method($handle))
383 || confess "You cannot overwrite a locally defined method ($handle) with a delegation";
26fbace8 384
d022f632 385 # NOTE:
386 # handles is not allowed to delegate
26fbace8 387 # any of these methods, as they will
388 # override the ones in your class, which
d022f632 389 # is almost certainly not what you want.
390 next if $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 391
452bac1b 392 if ((reftype($method_to_call) || '') eq 'CODE') {
26fbace8 393 $associated_class->add_method($handle => $method_to_call);
452bac1b 394 }
395 else {
396 $associated_class->add_method($handle => sub {
b805c70c 397 # FIXME
26fbace8 398 # we should check for lack of
399 # a callable return value from
400 # the accessor here
cbe25729 401 my $proxy = (shift)->$accessor_name();
402 @_ = ($proxy, @_);
403 goto &{ $proxy->can($method_to_call)};
452bac1b 404 });
405 }
406 }
407 }
26fbace8 408
452bac1b 409 return;
410}
411
98aae381 412# private methods to help delegation ...
413
452bac1b 414sub _canonicalize_handles {
415 my $self = shift;
416 my $handles = $self->handles;
c84f324f 417 if (my $handle_type = ref($handles)) {
418 if ($handle_type eq 'HASH') {
419 return %{$handles};
420 }
421 elsif ($handle_type eq 'ARRAY') {
422 return map { $_ => $_ } @{$handles};
423 }
424 elsif ($handle_type eq 'Regexp') {
425 ($self->has_type_constraint)
426 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
26fbace8 427 return map { ($_ => $_) }
c84f324f 428 grep { /$handles/ } $self->_get_delegate_method_list;
429 }
430 elsif ($handle_type eq 'CODE') {
431 return $handles->($self, $self->_find_delegate_metaclass);
432 }
433 else {
434 confess "Unable to canonicalize the 'handles' option with $handles";
435 }
452bac1b 436 }
437 else {
c84f324f 438 my $role_meta = eval { $handles->meta };
439 if ($@) {
26fbace8 440 confess "Unable to canonicalize the 'handles' option with $handles because : $@";
c84f324f 441 }
442
443 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
444 || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
26fbace8 445
c84f324f 446 return map { $_ => $_ } (
26fbace8 447 $role_meta->get_method_list,
c84f324f 448 $role_meta->get_required_method_list
449 );
452bac1b 450 }
451}
452
453sub _find_delegate_metaclass {
454 my $self = shift;
98aae381 455 if (my $class = $self->_isa_metadata) {
26fbace8 456 # if the class does have
452bac1b 457 # a meta method, use it
458 return $class->meta if $class->can('meta');
26fbace8 459 # otherwise we might be
452bac1b 460 # dealing with a non-Moose
26fbace8 461 # class, and need to make
452bac1b 462 # our own metaclass
463 return Moose::Meta::Class->initialize($class);
464 }
98aae381 465 elsif (my $role = $self->_does_metadata) {
26fbace8 466 # our role will always have
452bac1b 467 # a meta method
98aae381 468 return $role->meta;
452bac1b 469 }
470 else {
471 confess "Cannot find delegate metaclass for attribute " . $self->name;
472 }
473}
474
475sub _get_delegate_method_list {
476 my $self = shift;
477 my $meta = $self->_find_delegate_metaclass;
478 if ($meta->isa('Class::MOP::Class')) {
093b12c2 479 return map { $_->{name} } # NOTE: !never! delegate &meta
26fbace8 480 grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
452bac1b 481 $meta->compute_all_applicable_methods;
482 }
483 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 484 return $meta->get_method_list;
452bac1b 485 }
486 else {
487 confess "Unable to recognize the delegate metaclass '$meta'";
488 }
489}
490
c0e30cf5 4911;
492
493__END__
494
495=pod
496
497=head1 NAME
498
6ba6d68c 499Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 500
501=head1 DESCRIPTION
502
26fbace8 503This is a subclass of L<Class::MOP::Attribute> with Moose specific
504extensions.
6ba6d68c 505
26fbace8 506For the most part, the only time you will ever encounter an
507instance of this class is if you are doing some serious deep
508introspection. To really understand this class, you need to refer
6ba6d68c 509to the L<Class::MOP::Attribute> documentation.
e522431d 510
c0e30cf5 511=head1 METHODS
512
6ba6d68c 513=head2 Overridden methods
514
26fbace8 515These methods override methods in L<Class::MOP::Attribute> and add
516Moose specific features. You can safely assume though that they
6ba6d68c 517will behave just as L<Class::MOP::Attribute> does.
518
c0e30cf5 519=over 4
520
521=item B<new>
522
d500266f 523=item B<initialize_instance_slot>
524
452bac1b 525=item B<install_accessors>
526
39b3bc94 527=item B<accessor_metaclass>
528
946289d1 529=item B<get_value>
530
531=item B<set_value>
532
bcbaa845 533 eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
534 if($@) {
535 print "Oops: $@\n";
536 }
537
538I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
539
540Before setting the value, a check is made on the type constraint of
541the attribute, if it has one, to see if the value passes it. If the
542value fails to pass, the set operation dies with a L<Carp/confess>.
543
544Any coercion to convert values is done before checking the type constraint.
545
546To check a value against a type constraint before setting it, fetch the
547attribute instance using L<Moose::Meta::Attribute/find_attribute_by_name>,
548fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
549and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
550for an example.
551
a15dff8d 552=back
553
6ba6d68c 554=head2 Additional Moose features
555
26fbace8 556Moose attributes support type-constraint checking, weak reference
557creation and type coercion.
6ba6d68c 558
a15dff8d 559=over 4
560
9e93dd19 561=item B<clone_and_inherit_options>
562
26fbace8 563This is to support the C<has '+foo'> feature, it clones an attribute
564from a superclass and allows a very specific set of changes to be made
9e93dd19 565to the attribute.
566
a15dff8d 567=item B<has_type_constraint>
568
6ba6d68c 569Returns true if this meta-attribute has a type constraint.
570
a15dff8d 571=item B<type_constraint>
572
26fbace8 573A read-only accessor for this meta-attribute's type constraint. For
574more information on what you can do with this, see the documentation
6ba6d68c 575for L<Moose::Meta::TypeConstraint>.
a15dff8d 576
452bac1b 577=item B<has_handles>
578
579Returns true if this meta-attribute performs delegation.
580
581=item B<handles>
582
583This returns the value which was passed into the handles option.
584
6ba6d68c 585=item B<is_weak_ref>
a15dff8d 586
02a0fb52 587Returns true if this meta-attribute produces a weak reference.
4b598ea3 588
ca01a97b 589=item B<is_required>
590
02a0fb52 591Returns true if this meta-attribute is required to have a value.
ca01a97b 592
593=item B<is_lazy>
594
02a0fb52 595Returns true if this meta-attribute should be initialized lazily.
ca01a97b 596
26fbace8 597NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
598
599=item B<is_lazy_build>
600
601Returns true if this meta-attribute should be initialized lazily through
602the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
603make your attribute required and lazy. In addition it will set the builder, clearer
604and predicate options for you using the following convention.
605
606 #If your attribute name starts with an underscore:
607 has '_foo' => (lazy_build => 1);
608 #is the same as
58f85113 609 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
26fbace8 610 # or
58f85113 611 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
26fbace8 612
613 #If your attribute name does not start with an underscore:
58f85113 614 has 'foo' => (lazy_build => 1);
615 #is the same as
616 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
26fbace8 617 # or
58f85113 618 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
619
620The reason for the different naming of the C<builder> is that the C<builder>
621method is a private method while the C<clearer> and C<predicate> methods
622are public methods.
26fbace8 623
624NOTE: This means your class should provide a method whose name matches the value
58f85113 625of the builder part, in this case _build__foo or _build_foo.
ca01a97b 626
34a66aa3 627=item B<should_coerce>
4b598ea3 628
02a0fb52 629Returns true if this meta-attribute should perform type coercion.
6ba6d68c 630
536f0b17 631=item B<should_auto_deref>
632
26fbace8 633Returns true if this meta-attribute should perform automatic
634auto-dereferencing.
536f0b17 635
26fbace8 636NOTE: This can only be done for attributes whose type constraint is
536f0b17 637either I<ArrayRef> or I<HashRef>.
638
8c9d74e7 639=item B<has_trigger>
640
02a0fb52 641Returns true if this meta-attribute has a trigger set.
642
8c9d74e7 643=item B<trigger>
644
26fbace8 645This is a CODE reference which will be executed every time the
646value of an attribute is assigned. The CODE ref will get two values,
647the invocant and the new value. This can be used to handle I<basic>
02a0fb52 648bi-directional relations.
649
ddbdc0cb 650=item B<documentation>
651
26fbace8 652This is a string which contains the documentation for this attribute.
ddbdc0cb 653It serves no direct purpose right now, but it might in the future
654in some kind of automated documentation system perhaps.
655
656=item B<has_documentation>
657
658Returns true if this meta-attribute has any documentation.
659
c0e30cf5 660=back
661
662=head1 BUGS
663
26fbace8 664All complex software has bugs lurking in it, and this module is no
c0e30cf5 665exception. If you find a bug please either email me, or add the bug
666to cpan-RT.
667
c0e30cf5 668=head1 AUTHOR
669
670Stevan Little E<lt>stevan@iinteractive.comE<gt>
671
98aae381 672Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
673
c0e30cf5 674=head1 COPYRIGHT AND LICENSE
675
b77fdbed 676Copyright 2006, 2007 by Infinity Interactive, Inc.
c0e30cf5 677
678L<http://www.iinteractive.com>
679
680This library is free software; you can redistribute it and/or modify
26fbace8 681it under the same terms as Perl itself.
c0e30cf5 682
8a7a9c53 683=cut