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