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