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