some last minute tweaks
[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
d500266f 591=item B<initialize_instance_slot>
592
452bac1b 593=item B<install_accessors>
594
39b3bc94 595=item B<accessor_metaclass>
596
946289d1 597=item B<get_value>
598
599=item B<set_value>
600
bcbaa845 601 eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
602 if($@) {
603 print "Oops: $@\n";
604 }
605
606I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
607
608Before setting the value, a check is made on the type constraint of
609the attribute, if it has one, to see if the value passes it. If the
610value fails to pass, the set operation dies with a L<Carp/confess>.
611
612Any coercion to convert values is done before checking the type constraint.
613
614To check a value against a type constraint before setting it, fetch the
ec00fa75 615attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
bcbaa845 616fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
617and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
618for an example.
619
a15dff8d 620=back
621
6ba6d68c 622=head2 Additional Moose features
623
26fbace8 624Moose attributes support type-constraint checking, weak reference
625creation and type coercion.
6ba6d68c 626
a15dff8d 627=over 4
628
9e93dd19 629=item B<clone_and_inherit_options>
630
26fbace8 631This is to support the C<has '+foo'> feature, it clones an attribute
632from a superclass and allows a very specific set of changes to be made
9e93dd19 633to the attribute.
634
a15dff8d 635=item B<has_type_constraint>
636
6ba6d68c 637Returns true if this meta-attribute has a type constraint.
638
a15dff8d 639=item B<type_constraint>
640
26fbace8 641A read-only accessor for this meta-attribute's type constraint. For
642more information on what you can do with this, see the documentation
6ba6d68c 643for L<Moose::Meta::TypeConstraint>.
a15dff8d 644
452bac1b 645=item B<has_handles>
646
647Returns true if this meta-attribute performs delegation.
648
649=item B<handles>
650
651This returns the value which was passed into the handles option.
652
6ba6d68c 653=item B<is_weak_ref>
a15dff8d 654
02a0fb52 655Returns true if this meta-attribute produces a weak reference.
4b598ea3 656
ca01a97b 657=item B<is_required>
658
02a0fb52 659Returns true if this meta-attribute is required to have a value.
ca01a97b 660
661=item B<is_lazy>
662
02a0fb52 663Returns true if this meta-attribute should be initialized lazily.
ca01a97b 664
26fbace8 665NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
666
667=item B<is_lazy_build>
668
669Returns true if this meta-attribute should be initialized lazily through
670the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
671make your attribute required and lazy. In addition it will set the builder, clearer
672and predicate options for you using the following convention.
673
674 #If your attribute name starts with an underscore:
675 has '_foo' => (lazy_build => 1);
676 #is the same as
58f85113 677 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
26fbace8 678 # or
58f85113 679 has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
26fbace8 680
681 #If your attribute name does not start with an underscore:
58f85113 682 has 'foo' => (lazy_build => 1);
683 #is the same as
684 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
26fbace8 685 # or
58f85113 686 has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
687
688The reason for the different naming of the C<builder> is that the C<builder>
689method is a private method while the C<clearer> and C<predicate> methods
690are public methods.
26fbace8 691
692NOTE: This means your class should provide a method whose name matches the value
58f85113 693of the builder part, in this case _build__foo or _build_foo.
ca01a97b 694
34a66aa3 695=item B<should_coerce>
4b598ea3 696
02a0fb52 697Returns true if this meta-attribute should perform type coercion.
6ba6d68c 698
536f0b17 699=item B<should_auto_deref>
700
26fbace8 701Returns true if this meta-attribute should perform automatic
702auto-dereferencing.
536f0b17 703
26fbace8 704NOTE: This can only be done for attributes whose type constraint is
536f0b17 705either I<ArrayRef> or I<HashRef>.
706
8c9d74e7 707=item B<has_trigger>
708
02a0fb52 709Returns true if this meta-attribute has a trigger set.
710
8c9d74e7 711=item B<trigger>
712
26fbace8 713This is a CODE reference which will be executed every time the
714value of an attribute is assigned. The CODE ref will get two values,
715the invocant and the new value. This can be used to handle I<basic>
02a0fb52 716bi-directional relations.
717
ddbdc0cb 718=item B<documentation>
719
26fbace8 720This is a string which contains the documentation for this attribute.
ddbdc0cb 721It serves no direct purpose right now, but it might in the future
722in some kind of automated documentation system perhaps.
723
724=item B<has_documentation>
725
726Returns true if this meta-attribute has any documentation.
727
c0e30cf5 728=back
729
730=head1 BUGS
731
26fbace8 732All complex software has bugs lurking in it, and this module is no
c0e30cf5 733exception. If you find a bug please either email me, or add the bug
734to cpan-RT.
735
c0e30cf5 736=head1 AUTHOR
737
738Stevan Little E<lt>stevan@iinteractive.comE<gt>
739
98aae381 740Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
741
c0e30cf5 742=head1 COPYRIGHT AND LICENSE
743
778db3ac 744Copyright 2006-2008 by Infinity Interactive, Inc.
c0e30cf5 745
746L<http://www.iinteractive.com>
747
748This library is free software; you can redistribute it and/or modify
26fbace8 749it under the same terms as Perl itself.
c0e30cf5 750
8a7a9c53 751=cut