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