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