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