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