Mention that the import method can take a into argument in
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint.pm
CommitLineData
4e036ee4 1
2package Moose::Meta::TypeConstraint;
3
4use strict;
5use warnings;
6use metaclass;
7
ed90007b 8use overload '0+' => sub { refaddr(shift) }, # id an object
9 '""' => sub { shift->name }, # stringify to tc name
72e389bf 10 bool => sub { 1 },
b644e331 11 fallback => 1;
900466d6 12
477a812e 13use Eval::Closure;
dabed765 14use Scalar::Util qw(blessed refaddr);
9f2230e9 15use Sub::Name qw(subname);
5a18346b 16use Try::Tiny;
66811d63 17
e606ae5f 18use base qw(Class::MOP::Object);
19
dc2b7cc8 20__PACKAGE__->meta->add_attribute('name' => (
21 reader => 'name',
22 Class::MOP::_definition_context(),
23));
3726f905 24__PACKAGE__->meta->add_attribute('parent' => (
25 reader => 'parent',
26 predicate => 'has_parent',
dc2b7cc8 27 Class::MOP::_definition_context(),
3726f905 28));
baf26cc6 29
30my $null_constraint = sub { 1 };
d67145ed 31__PACKAGE__->meta->add_attribute('constraint' => (
8de73ff1 32 reader => 'constraint',
33 writer => '_set_constraint',
dc2b7cc8 34 default => sub { $null_constraint },
35 Class::MOP::_definition_context(),
d67145ed 36));
dc2b7cc8 37
76d37e5a 38__PACKAGE__->meta->add_attribute('message' => (
39 accessor => 'message',
dc2b7cc8 40 predicate => 'has_message',
41 Class::MOP::_definition_context(),
76d37e5a 42));
dc2b7cc8 43
92a88343 44__PACKAGE__->meta->add_attribute('_default_message' => (
45 accessor => '_default_message',
dc2b7cc8 46 Class::MOP::_definition_context(),
92a88343 47));
dc2b7cc8 48
92a88343 49# can't make this a default because it has to close over the type name, and
50# cmop attributes don't have lazy
51my $_default_message_generator = sub {
52 my $name = shift;
53 sub {
54 my $value = shift;
55 # have to load it late like this, since it uses Moose itself
56 my $can_partialdump = try {
57 # versions prior to 0.14 had a potential infinite loop bug
58 Class::MOP::load_class('Devel::PartialDump', { -version => 0.14 });
59 1;
60 };
61 if ($can_partialdump) {
62 $value = Devel::PartialDump->new->dump($value);
63 }
64 else {
65 $value = (defined $value ? overload::StrVal($value) : 'undef');
66 }
67 return "Validation failed for '" . $name . "' with value $value";
68 }
69};
a27aa600 70__PACKAGE__->meta->add_attribute('coercion' => (
71 accessor => 'coercion',
dc2b7cc8 72 predicate => 'has_coercion',
73 Class::MOP::_definition_context(),
a27aa600 74));
70ea9161 75
c8cf9aaa 76__PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
77 init_arg => 'optimized',
78 accessor => 'hand_optimized_type_constraint',
e27dfc11 79 predicate => 'has_hand_optimized_type_constraint',
dc2b7cc8 80 Class::MOP::_definition_context(),
c8cf9aaa 81));
82
4e36cf24 83__PACKAGE__->meta->add_attribute('inlined' => (
7487e61c 84 init_arg => 'inlined',
4e36cf24 85 accessor => 'inlined',
7487e61c 86 predicate => '_has_inlined_type_constraint',
dc2b7cc8 87 Class::MOP::_definition_context(),
4e36cf24 88));
89
9c44971f 90__PACKAGE__->meta->add_attribute('inline_environment' => (
91 init_arg => 'inline_environment',
ca789903 92 accessor => '_inline_environment',
9c44971f 93 default => sub { {} },
dc2b7cc8 94 Class::MOP::_definition_context(),
9c44971f 95));
96
bd72f3c8 97sub parents {
98 my $self;
99 $self->parent;
100}
101
3726f905 102# private accessors
103
104__PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
105 accessor => '_compiled_type_constraint',
dc2b7cc8 106 predicate => '_has_compiled_type_constraint',
107 Class::MOP::_definition_context(),
3726f905 108));
dc2b7cc8 109
22aed3c0 110__PACKAGE__->meta->add_attribute('package_defined_in' => (
dc2b7cc8 111 accessor => '_package_defined_in',
112 Class::MOP::_definition_context(),
22aed3c0 113));
114
e27dfc11 115sub new {
a27aa600 116 my $class = shift;
8534c69a 117 my ($first, @rest) = @_;
118 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
119 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
70ea9161 120
7ec88c15 121 if ( $args{optimized} ) {
122 Moose::Deprecated::deprecated(
123 feature => 'optimized type constraint sub ref',
124 message =>
125 'Providing an optimized subroutine ref for type constraints is deprecated.'
126 . ' Use the inlining feature (inline_as) instead.'
127 );
128 }
129
8534c69a 130 my $self = $class->_new(%args);
3726f905 131 $self->compile_type_constraint()
132 unless $self->_has_compiled_type_constraint;
92a88343 133 $self->_default_message($_default_message_generator->($self->name))
134 unless $self->has_message;
66811d63 135 return $self;
136}
137
8534c69a 138
139
70ea9161 140sub coerce {
141 my $self = shift;
142
143 my $coercion = $self->coercion;
144
145 unless ($coercion) {
146 require Moose;
147 Moose->throw_error("Cannot coerce without a type coercion");
148 }
149
02679ba4 150 return $_[0] if $self->check($_[0]);
151
70ea9161 152 return $coercion->coerce(@_);
153}
a1257460 154
bb6ac54a 155sub assert_coerce {
156 my $self = shift;
157
158 my $coercion = $self->coercion;
159
160 unless ($coercion) {
161 require Moose;
162 Moose->throw_error("Cannot coerce without a type coercion");
163 }
164
165 return $_[0] if $self->check($_[0]);
166
167 my $result = $coercion->coerce(@_);
168
169 $self->assert_valid($result);
170
171 return $result;
172}
173
a1257460 174sub check {
175 my ($self, @args) = @_;
176 my $constraint_subref = $self->_compiled_type_constraint;
177 return $constraint_subref->(@args) ? 1 : undef;
178}
179
e27dfc11 180sub validate {
76d37e5a 181 my ($self, $value) = @_;
182 if ($self->_compiled_type_constraint->($value)) {
183 return undef;
184 }
185 else {
688fcdda 186 $self->get_message($value);
76d37e5a 187 }
188}
189
7c047a36 190sub can_be_inlined {
7487e61c 191 my $self = shift;
192
92efe680 193 if ( $self->has_parent && $self->constraint == $null_constraint ) {
7c047a36 194 return $self->parent->can_be_inlined;
7487e61c 195 }
196
197 return $self->_has_inlined_type_constraint;
198}
199
4e36cf24 200sub _inline_check {
201 my $self = shift;
202
7c047a36 203 unless ( $self->can_be_inlined ) {
3f9c18f3 204 require Moose;
205 Moose->throw_error( 'Cannot inline a type constraint check for ' . $self->name );
206 }
4e36cf24 207
92efe680 208 if ( $self->has_parent && $self->constraint == $null_constraint ) {
7487e61c 209 return $self->parent->_inline_check(@_);
210 }
211
e6fff671 212 return '( do { ' . $self->inlined->( $self, @_ ) . ' } )';
4e36cf24 213}
214
ca789903 215sub inline_environment {
216 my $self = shift;
217
218 if ( $self->has_parent && $self->constraint == $null_constraint ) {
219 return $self->parent->inline_environment;
220 }
221
222 return $self->_inline_environment;
223}
224
c24269b3 225sub assert_valid {
226 my ($self, $value) = @_;
227
228 my $error = $self->validate($value);
229 return 1 if ! defined $error;
230
231 require Moose;
232 Moose->throw_error($error);
233}
234
688fcdda 235sub get_message {
236 my ($self, $value) = @_;
92a88343 237 my $msg = $self->message || $self->_default_message;
238 local $_ = $value;
239 return $msg->($value);
688fcdda 240}
241
3726f905 242## type predicates ...
243
d9e17f80 244sub equals {
245 my ( $self, $type_or_name ) = @_;
246
e606ae5f 247 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
dabed765 248
0677975f 249 return 1 if $self == $other;
dabed765 250
251 if ( $self->has_hand_optimized_type_constraint and $other->has_hand_optimized_type_constraint ) {
252 return 1 if $self->hand_optimized_type_constraint == $other->hand_optimized_type_constraint;
253 }
254
255 return unless $self->constraint == $other->constraint;
256
257 if ( $self->has_parent ) {
258 return unless $other->has_parent;
259 return unless $self->parent->equals( $other->parent );
260 } else {
261 return if $other->has_parent;
262 }
d9e17f80 263
05a5763c 264 return;
d9e17f80 265}
266
b26e162e 267sub is_a_type_of {
d9e17f80 268 my ($self, $type_or_name) = @_;
269
e606ae5f 270 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
d9e17f80 271
272 ($self->equals($type) || $self->is_subtype_of($type));
b26e162e 273}
274
cce8198b 275sub is_subtype_of {
d9e17f80 276 my ($self, $type_or_name) = @_;
277
e606ae5f 278 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name) or return;
d9e17f80 279
cce8198b 280 my $current = $self;
d9e17f80 281
cce8198b 282 while (my $parent = $current->parent) {
d9e17f80 283 return 1 if $parent->equals($type);
cce8198b 284 $current = $parent;
285 }
d9e17f80 286
cce8198b 287 return 0;
288}
289
3726f905 290## compiling the type constraint
291
292sub compile_type_constraint {
293 my $self = shift;
294 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
451c8248 295}
296
3726f905 297## type compilers ...
298
299sub _actually_compile_type_constraint {
300 my $self = shift;
e27dfc11 301
3726f905 302 return $self->_compile_hand_optimized_type_constraint
303 if $self->has_hand_optimized_type_constraint;
e27dfc11 304
7c047a36 305 if ( $self->can_be_inlined ) {
477a812e 306 return eval_closure(
9c44971f 307 source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
308 environment => $self->inline_environment,
477a812e 309 );
43837b8a 310 }
311
3726f905 312 my $check = $self->constraint;
70ea9161 313 unless ( defined $check ) {
314 require Moose;
315 Moose->throw_error( "Could not compile type constraint '"
e27dfc11 316 . $self->name
70ea9161 317 . "' because no constraint check" );
318 }
e27dfc11 319
3726f905 320 return $self->_compile_subtype($check)
321 if $self->has_parent;
e27dfc11 322
3726f905 323 return $self->_compile_type($check);
324}
325
326sub _compile_hand_optimized_type_constraint {
327 my $self = shift;
e27dfc11 328
3726f905 329 my $type_constraint = $self->hand_optimized_type_constraint;
e27dfc11 330
70ea9161 331 unless ( ref $type_constraint ) {
332 require Moose;
70ea9161 333 Moose->throw_error("Hand optimized type constraint is not a code reference");
334 }
42bc21a4 335
336 return $type_constraint;
3726f905 337}
338
339sub _compile_subtype {
340 my ($self, $check) = @_;
e27dfc11 341
baf26cc6 342 # gather all the parent constraintss in order
3726f905 343 my @parents;
baf26cc6 344 my $optimized_parent;
3726f905 345 foreach my $parent ($self->_collect_all_parents) {
baf26cc6 346 # if a parent is optimized, the optimized constraint already includes
347 # all of its parents tcs, so we can break the loop
3726f905 348 if ($parent->has_hand_optimized_type_constraint) {
baf26cc6 349 push @parents => $optimized_parent = $parent->hand_optimized_type_constraint;
e27dfc11 350 last;
3726f905 351 }
352 else {
baf26cc6 353 push @parents => $parent->constraint;
3726f905 354 }
355 }
e27dfc11 356
baf26cc6 357 @parents = grep { $_ != $null_constraint } reverse @parents;
358
359 unless ( @parents ) {
360 return $self->_compile_type($check);
361 } elsif( $optimized_parent and @parents == 1 ) {
362 # the case of just one optimized parent is optimized to prevent
363 # looping and the unnecessary localization
b5981f07 364 if ( $check == $null_constraint ) {
365 return $optimized_parent;
366 } else {
9f2230e9 367 return subname($self->name, sub {
b5981f07 368 return undef unless $optimized_parent->($_[0]);
a1257460 369 my (@args) = @_;
370 local $_ = $args[0];
371 $check->(@args);
b5981f07 372 });
373 }
baf26cc6 374 } else {
375 # general case, check all the constraints, from the first parent to ourselves
b5981f07 376 my @checks = @parents;
377 push @checks, $check if $check != $null_constraint;
9f2230e9 378 return subname($self->name => sub {
a1257460 379 my (@args) = @_;
380 local $_ = $args[0];
baf26cc6 381 foreach my $check (@checks) {
a1257460 382 return undef unless $check->(@args);
baf26cc6 383 }
384 return 1;
385 });
386 }
3726f905 387}
388
389sub _compile_type {
390 my ($self, $check) = @_;
baf26cc6 391
392 return $check if $check == $null_constraint; # Item, Any
393
9f2230e9 394 return subname($self->name => sub {
a1257460 395 my (@args) = @_;
396 local $_ = $args[0];
397 $check->(@args);
1b2aea39 398 });
3726f905 399}
400
401## other utils ...
402
403sub _collect_all_parents {
404 my $self = shift;
405 my @parents;
406 my $current = $self->parent;
407 while (defined $current) {
408 push @parents => $current;
409 $current = $current->parent;
410 }
411 return @parents;
412}
413
85a9908f 414sub create_child_type {
9ceb576e 415 my ($self, %opts) = @_;
416 my $class = ref $self;
417 return $class->new(%opts, parent => $self);
418}
419
4e036ee4 4201;
421
ad46f524 422# ABSTRACT: The Moose Type Constraint metaclass
423
4e036ee4 424__END__
425
426=pod
427
4e036ee4 428=head1 DESCRIPTION
429
cfd006f0 430This class represents a single type constraint. Moose's built-in type
76127c77 431constraints, as well as constraints you define, are all stored in a
cfd006f0 432L<Moose::Meta::TypeConstraint::Registry> object as objects of this
433class.
6ba6d68c 434
baf46b9e 435=head1 INHERITANCE
436
437C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
438
4e036ee4 439=head1 METHODS
440
441=over 4
442
cfd006f0 443=item B<< Moose::Meta::TypeConstraint->new(%options) >>
4e036ee4 444
cfd006f0 445This creates a new type constraint based on the provided C<%options>:
4e036ee4 446
cfd006f0 447=over 8
d9e17f80 448
cfd006f0 449=item * name
e606ae5f 450
cfd006f0 451The constraint name. If a name is not provided, it will be set to
452"__ANON__".
b26e162e 453
cfd006f0 454=item * parent
b26e162e 455
cfd006f0 456A C<Moose::Meta::TypeConstraint> object which is the parent type for
457the type being created. This is optional.
cce8198b 458
cfd006f0 459=item * constraint
e606ae5f 460
cfd006f0 461This is the subroutine reference that implements the actual constraint
462check. This defaults to a subroutine which always returns true.
6ba6d68c 463
cfd006f0 464=item * message
0a5bd159 465
cfd006f0 466A subroutine reference which is used to generate an error message when
467the constraint fails. This is optional.
0a5bd159 468
cfd006f0 469=item * coercion
76d37e5a 470
cfd006f0 471A L<Moose::Meta::TypeCoercion> object representing the coercions to
472the type. This is optional.
76d37e5a 473
7142d232 474=item * inlined
475
476A subroutine which returns a string suitable for inlining this type
477constraint. It will be called as a method on the type constraint object, and
478will receive a single additional parameter, a variable name to be tested
479(usually C<"$_"> or C<"$_[0]">.
480
481This is optional.
482
483=item * inline_environment
484
485A hash reference of variables to close over. The keys are variables names, and
486the values are I<references> to the variables.
487
cfd006f0 488=item * optimized
76d37e5a 489
7142d232 490B<This option is deprecated.>
491
cfd006f0 492This is a variant of the C<constraint> parameter that is somehow
493optimized. Typically, this means incorporating both the type's
494constraint and all of its parents' constraints into a single
495subroutine reference.
6ba6d68c 496
cfd006f0 497=back
4e036ee4 498
cfd006f0 499=item B<< $constraint->equals($type_name_or_object) >>
e606ae5f 500
cfd006f0 501Returns true if the supplied name or type object is the same as the
502current type.
66811d63 503
cfd006f0 504=item B<< $constraint->is_subtype_of($type_name_or_object) >>
e606ae5f 505
cfd006f0 506Returns true if the supplied name or type object is a parent of the
507current type.
3726f905 508
cfd006f0 509=item B<< $constraint->is_a_type_of($type_name_or_object) >>
e606ae5f 510
cfd006f0 511Returns true if the given type is the same as the current type, or is
512a parent of the current type. This is a shortcut for checking
513C<equals> and C<is_subtype_of>.
d9e17f80 514
cfd006f0 515=item B<< $constraint->coerce($value) >>
2f7e4042 516
b2894aea 517This will attempt to coerce the value to the type. If the type does not
cfd006f0 518have any defined coercions this will throw an error.
66811d63 519
572b5187 520If no coercion can produce a value matching C<$constraint>, the original
521value is returned.
522
086c6b6c 523=item B<< $constraint->assert_coerce($value) >>
572b5187 524
525This method behaves just like C<coerce>, but if the result is not valid
526according to C<$constraint>, an error is thrown.
527
cfd006f0 528=item B<< $constraint->check($value) >>
2f7e4042 529
cfd006f0 530Returns true if the given value passes the constraint for the type.
76d37e5a 531
cfd006f0 532=item B<< $constraint->validate($value) >>
2f7e4042 533
cfd006f0 534This is similar to C<check>. However, if the type I<is valid> then the
535method returns an explicit C<undef>. If the type is not valid, we call
536C<< $self->get_message($value) >> internally to generate an error
537message.
76d37e5a 538
952320e0 539=item B<< $constraint->assert_valid($value) >>
540
541Like C<check> and C<validate>, this method checks whether C<$value> is
542valid under the constraint. If it is, it will return true. If it is not,
543an exception will be thrown with the results of
544C<< $self->get_message($value) >>.
545
cfd006f0 546=item B<< $constraint->name >>
2f7e4042 547
cfd006f0 548Returns the type's name, as provided to the constructor.
688fcdda 549
cfd006f0 550=item B<< $constraint->parent >>
2f7e4042 551
cfd006f0 552Returns the type's parent, as provided to the constructor, if any.
4e036ee4 553
cfd006f0 554=item B<< $constraint->has_parent >>
2f7e4042 555
cfd006f0 556Returns true if the type has a parent type.
a27aa600 557
cfd006f0 558=item B<< $constraint->parents >>
2f7e4042 559
cfd006f0 560A synonym for C<parent>. This is useful for polymorphism with types
561that can have more than one parent.
c8cf9aaa 562
cfd006f0 563=item B<< $constraint->constraint >>
c8cf9aaa 564
cfd006f0 565Returns the type's constraint, as provided to the constructor.
9ceb576e 566
cfd006f0 567=item B<< $constraint->get_message($value) >>
4e036ee4 568
cfd006f0 569This generates a method for the given value. If the type does not have
570an explicit message, we generate a default message.
3726f905 571
cfd006f0 572=item B<< $constraint->has_message >>
573
574Returns true if the type has a message.
575
576=item B<< $constraint->message >>
577
578Returns the type's message as a subroutine reference.
579
580=item B<< $constraint->coercion >>
581
582Returns the type's L<Moose::Meta::TypeCoercion> object, if one
583exists.
584
585=item B<< $constraint->has_coercion >>
586
587Returns true if the type has a coercion.
588
7142d232 589=item B<< $constraint->can_be_inlined >>
590
591Returns true if this type constraint can be inlined. A type constraint which
592subtypes an inlinable constraint and does not add an additional constraint
593"inherits" its parent type's inlining.
594
cfd006f0 595=item B<< $constraint->hand_optimized_type_constraint >>
596
7142d232 597B<This method is deprecated.>
598
cfd006f0 599Returns the type's hand optimized constraint, as provided to the
600constructor via the C<optimized> option.
601
602=item B<< $constraint->has_hand_optimized_type_constraint >>
603
7142d232 604B<This method is deprecated.>
605
cfd006f0 606Returns true if the type has an optimized constraint.
607
608=item B<< $constraint->create_child_type(%options) >>
451c8248 609
cfd006f0 610This returns a new type constraint of the same class using the
611provided C<%options>. The C<parent> option will be the current type.
3726f905 612
cfd006f0 613This method exists so that subclasses of this class can override this
614behavior and change how child types are created.
451c8248 615
616=back
617
4e036ee4 618=head1 BUGS
619
d4048ef3 620See L<Moose/BUGS> for details on reporting bugs.
4e036ee4 621
c8cf9aaa 622=cut