be a little more anal about when we skip certain methods for delegation
[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.
4fe78472 397
398 # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
399 #cluck("Not delegating method '$handle' because it is a core method") and
400 next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
26fbace8 401
452bac1b 402 if ((reftype($method_to_call) || '') eq 'CODE') {
26fbace8 403 $associated_class->add_method($handle => $method_to_call);
452bac1b 404 }
405 else {
406 $associated_class->add_method($handle => sub {
b805c70c 407 # FIXME
26fbace8 408 # we should check for lack of
409 # a callable return value from
410 # the accessor here
f3c4e20e 411 my $proxy = (shift)->$accessor();
cbe25729 412 @_ = ($proxy, @_);
f3c4e20e 413 goto &{ $proxy->can($method_to_call) };
452bac1b 414 });
415 }
416 }
417 }
26fbace8 418
452bac1b 419 return;
420}
421
98aae381 422# private methods to help delegation ...
423
452bac1b 424sub _canonicalize_handles {
425 my $self = shift;
426 my $handles = $self->handles;
c84f324f 427 if (my $handle_type = ref($handles)) {
428 if ($handle_type eq 'HASH') {
429 return %{$handles};
430 }
431 elsif ($handle_type eq 'ARRAY') {
432 return map { $_ => $_ } @{$handles};
433 }
434 elsif ($handle_type eq 'Regexp') {
435 ($self->has_type_constraint)
436 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
26fbace8 437 return map { ($_ => $_) }
c84f324f 438 grep { /$handles/ } $self->_get_delegate_method_list;
439 }
440 elsif ($handle_type eq 'CODE') {
441 return $handles->($self, $self->_find_delegate_metaclass);
442 }
443 else {
444 confess "Unable to canonicalize the 'handles' option with $handles";
445 }
452bac1b 446 }
447 else {
c84f324f 448 my $role_meta = eval { $handles->meta };
449 if ($@) {
26fbace8 450 confess "Unable to canonicalize the 'handles' option with $handles because : $@";
c84f324f 451 }
452
453 (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
454 || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
26fbace8 455
c84f324f 456 return map { $_ => $_ } (
26fbace8 457 $role_meta->get_method_list,
c84f324f 458 $role_meta->get_required_method_list
459 );
452bac1b 460 }
461}
462
463sub _find_delegate_metaclass {
464 my $self = shift;
98aae381 465 if (my $class = $self->_isa_metadata) {
26fbace8 466 # if the class does have
452bac1b 467 # a meta method, use it
468 return $class->meta if $class->can('meta');
26fbace8 469 # otherwise we might be
452bac1b 470 # dealing with a non-Moose
26fbace8 471 # class, and need to make
452bac1b 472 # our own metaclass
473 return Moose::Meta::Class->initialize($class);
474 }
98aae381 475 elsif (my $role = $self->_does_metadata) {
26fbace8 476 # our role will always have
452bac1b 477 # a meta method
98aae381 478 return $role->meta;
452bac1b 479 }
480 else {
481 confess "Cannot find delegate metaclass for attribute " . $self->name;
482 }
483}
484
485sub _get_delegate_method_list {
486 my $self = shift;
487 my $meta = $self->_find_delegate_metaclass;
488 if ($meta->isa('Class::MOP::Class')) {
093b12c2 489 return map { $_->{name} } # NOTE: !never! delegate &meta
26fbace8 490 grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
452bac1b 491 $meta->compute_all_applicable_methods;
492 }
493 elsif ($meta->isa('Moose::Meta::Role')) {
26fbace8 494 return $meta->get_method_list;
452bac1b 495 }
496 else {
497 confess "Unable to recognize the delegate metaclass '$meta'";
498 }
499}
500
c0e30cf5 5011;
502
503__END__
504
505=pod
506
507=head1 NAME
508
6ba6d68c 509Moose::Meta::Attribute - The Moose attribute metaclass
c0e30cf5 510
511=head1 DESCRIPTION
512
26fbace8 513This is a subclass of L<Class::MOP::Attribute> with Moose specific
514extensions.
6ba6d68c 515
26fbace8 516For the most part, the only time you will ever encounter an
517instance of this class is if you are doing some serious deep
518introspection. To really understand this class, you need to refer
6ba6d68c 519to the L<Class::MOP::Attribute> documentation.
e522431d 520
c0e30cf5 521=head1 METHODS
522
6ba6d68c 523=head2 Overridden methods
524
26fbace8 525These methods override methods in L<Class::MOP::Attribute> and add
526Moose specific features. You can safely assume though that they
6ba6d68c 527will behave just as L<Class::MOP::Attribute> does.
528
c0e30cf5 529=over 4
530
531=item B<new>
532
d500266f 533=item B<initialize_instance_slot>
534
452bac1b 535=item B<install_accessors>
536
39b3bc94 537=item B<accessor_metaclass>
538
946289d1 539=item B<get_value>
540
541=item B<set_value>
542
bcbaa845 543 eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
544 if($@) {
545 print "Oops: $@\n";
546 }
547
548I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
549
550Before setting the value, a check is made on the type constraint of
551the attribute, if it has one, to see if the value passes it. If the
552value fails to pass, the set operation dies with a L<Carp/confess>.
553
554Any coercion to convert values is done before checking the type constraint.
555
556To check a value against a type constraint before setting it, fetch the
ec00fa75 557attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 558fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
559and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
560for an example.
561
a15dff8d 562=back
563
6ba6d68c 564=head2 Additional Moose features
565
26fbace8 566Moose attributes support type-constraint checking, weak reference
567creation and type coercion.
6ba6d68c 568
a15dff8d 569=over 4
570
9e93dd19 571=item B<clone_and_inherit_options>
572
26fbace8 573This is to support the C<has '+foo'> feature, it clones an attribute
574from a superclass and allows a very specific set of changes to be made
9e93dd19 575to the attribute.
576
a15dff8d 577=item B<has_type_constraint>
578
6ba6d68c 579Returns true if this meta-attribute has a type constraint.
580
a15dff8d 581=item B<type_constraint>
582
26fbace8 583A read-only accessor for this meta-attribute's type constraint. For
584more information on what you can do with this, see the documentation
6ba6d68c 585for L<Moose::Meta::TypeConstraint>.
a15dff8d 586
452bac1b 587=item B<has_handles>
588
589Returns true if this meta-attribute performs delegation.
590
591=item B<handles>
592
593This returns the value which was passed into the handles option.
594
6ba6d68c 595=item B<is_weak_ref>
a15dff8d 596
02a0fb52 597Returns true if this meta-attribute produces a weak reference.
4b598ea3 598
ca01a97b 599=item B<is_required>
600
02a0fb52 601Returns true if this meta-attribute is required to have a value.
ca01a97b 602
603=item B<is_lazy>
604
02a0fb52 605Returns true if this meta-attribute should be initialized lazily.
ca01a97b 606
26fbace8 607NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
608
609=item B<is_lazy_build>
610
611Returns true if this meta-attribute should be initialized lazily through
612the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
613make your attribute required and lazy. In addition it will set the builder, clearer
614and predicate options for you using the following convention.
615
616 #If your attribute name starts with an underscore:
617 has '_foo' => (lazy_build => 1);
618 #is the same as
58f85113 619 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
26fbace8 620 # or
58f85113 621 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
26fbace8 622
623 #If your attribute name does not start with an underscore:
58f85113 624 has 'foo' => (lazy_build => 1);
625 #is the same as
626 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
26fbace8 627 # or
58f85113 628 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
629
630The reason for the different naming of the C<builder> is that the C<builder>
631method is a private method while the C<clearer> and C<predicate> methods
632are public methods.
26fbace8 633
634NOTE: This means your class should provide a method whose name matches the value
58f85113 635of the builder part, in this case _build__foo or _build_foo.
ca01a97b 636
34a66aa3 637=item B<should_coerce>
4b598ea3 638
02a0fb52 639Returns true if this meta-attribute should perform type coercion.
6ba6d68c 640
536f0b17 641=item B<should_auto_deref>
642
26fbace8 643Returns true if this meta-attribute should perform automatic
644auto-dereferencing.
536f0b17 645
26fbace8 646NOTE: This can only be done for attributes whose type constraint is
536f0b17 647either I<ArrayRef> or I<HashRef>.
648
8c9d74e7 649=item B<has_trigger>
650
02a0fb52 651Returns true if this meta-attribute has a trigger set.
652
8c9d74e7 653=item B<trigger>
654
26fbace8 655This is a CODE reference which will be executed every time the
656value of an attribute is assigned. The CODE ref will get two values,
657the invocant and the new value. This can be used to handle I<basic>
02a0fb52 658bi-directional relations.
659
ddbdc0cb 660=item B<documentation>
661
26fbace8 662This is a string which contains the documentation for this attribute.
ddbdc0cb 663It serves no direct purpose right now, but it might in the future
664in some kind of automated documentation system perhaps.
665
666=item B<has_documentation>
667
668Returns true if this meta-attribute has any documentation.
669
c0e30cf5 670=back
671
672=head1 BUGS
673
26fbace8 674All complex software has bugs lurking in it, and this module is no
c0e30cf5 675exception. If you find a bug please either email me, or add the bug
676to cpan-RT.
677
c0e30cf5 678=head1 AUTHOR
679
680Stevan Little E<lt>stevan@iinteractive.comE<gt>
681
98aae381 682Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
683
c0e30cf5 684=head1 COPYRIGHT AND LICENSE
685
778db3ac 686Copyright 2006-2008 by Infinity Interactive, Inc.
c0e30cf5 687
688L<http://www.iinteractive.com>
689
690This library is free software; you can redistribute it and/or modify
26fbace8 691it under the same terms as Perl itself.
c0e30cf5 692
8a7a9c53 693=cut