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