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