File Coverage

blib/lib/Moose/Meta/TypeConstraint.pm
Criterion Covered Total %
statement 145 147 98.6
branch 61 68 89.7
condition 13 15 86.6
subroutine 35 35 100.0
pod 14 15 93.3
total 268 280 95.7


line stmt bran cond sub pod time code
1             package Moose::Meta::TypeConstraint;
2             our $VERSION = '2.2206';
3              
4 390     390   73478 use strict;
  390         972  
  390         12648  
5 390     390   2209 use warnings;
  390         910  
  390         9971  
6 390     390   154363 use metaclass;
  390         1040  
  390         2381  
7              
8 3529     3529   15116 use overload '0+' => sub { refaddr(shift) }, # id an object
9 169     169   24554 '""' => sub { shift->name }, # stringify to tc name
10 90163     90163   296574 bool => sub { 1 },
11 390     390   4571 fallback => 1;
  390         1091  
  390         7729  
12              
13 390     390   50530 use Eval::Closure;
  390         1056  
  390         29367  
14 390     390   5253 use Scalar::Util qw(refaddr);
  390         1030  
  390         23516  
15 390     390   2701 use Sub::Util qw(set_subname);
  390         1038  
  390         22628  
16 390     390   2634 use Try::Tiny;
  390         971  
  390         22691  
17              
18 390     390   2791 use parent 'Class::MOP::Object';
  390         991  
  390         4299  
19              
20 390     390   30287 use Moose::Util 'throw_exception';
  390         1196  
  390         4359  
21              
22             __PACKAGE__->meta->add_attribute('name' => (
23             reader => 'name',
24             Class::MOP::_definition_context(),
25             ));
26             __PACKAGE__->meta->add_attribute('parent' => (
27             reader => 'parent',
28             predicate => 'has_parent',
29             Class::MOP::_definition_context(),
30             ));
31              
32             my $null_constraint = sub { 1 };
33             __PACKAGE__->meta->add_attribute('constraint' => (
34             reader => 'constraint',
35             writer => '_set_constraint',
36             default => sub { $null_constraint },
37             Class::MOP::_definition_context(),
38             ));
39              
40             __PACKAGE__->meta->add_attribute('message' => (
41             accessor => 'message',
42             predicate => 'has_message',
43             Class::MOP::_definition_context(),
44             ));
45              
46             __PACKAGE__->meta->add_attribute('_default_message' => (
47             accessor => '_default_message',
48             Class::MOP::_definition_context(),
49             ));
50              
51             # can't make this a default because it has to close over the type name, and
52             # cmop attributes don't have lazy
53             my $_default_message_generator = sub {
54             my $name = shift;
55             sub {
56             my $value = shift;
57             # have to load it late like this, since it uses Moose itself
58             my $can_partialdump = try {
59             # versions prior to 0.14 had a potential infinite loop bug
60             require Devel::PartialDump;
61             Devel::PartialDump->VERSION(0.14);
62             1;
63             };
64             if ($can_partialdump) {
65             $value = Devel::PartialDump->new->dump($value);
66             }
67             else {
68             $value = (defined $value ? overload::StrVal($value) : 'undef');
69             }
70             return "Validation failed for '" . $name . "' with value $value";
71             }
72             };
73             __PACKAGE__->meta->add_attribute('coercion' => (
74             accessor => 'coercion',
75             predicate => 'has_coercion',
76             Class::MOP::_definition_context(),
77             ));
78              
79             __PACKAGE__->meta->add_attribute('inlined' => (
80             init_arg => 'inlined',
81             accessor => 'inlined',
82             predicate => '_has_inlined_type_constraint',
83             Class::MOP::_definition_context(),
84             ));
85              
86             __PACKAGE__->meta->add_attribute('inline_environment' => (
87             init_arg => 'inline_environment',
88             accessor => '_inline_environment',
89             default => sub { {} },
90             Class::MOP::_definition_context(),
91             ));
92              
93             sub parents {
94 1     1 1 4 my $self = shift;
95 1         5 $self->parent;
96             }
97              
98             # private accessors
99              
100             __PACKAGE__->meta->add_attribute('compiled_type_constraint' => (
101             accessor => '_compiled_type_constraint',
102             predicate => '_has_compiled_type_constraint',
103             Class::MOP::_definition_context(),
104             ));
105              
106             __PACKAGE__->meta->add_attribute('package_defined_in' => (
107             accessor => '_package_defined_in',
108             Class::MOP::_definition_context(),
109             ));
110              
111             sub new {
112 11624     11624 1 26626 my $class = shift;
113 11624         34062 my ($first, @rest) = @_;
114 11624 100       58776 my %args = ref $first ? %$first : $first ? ($first, @rest) : ();
    100          
115 11624 100       40116 $args{name} = $args{name} ? "$args{name}" : "__ANON__";
116              
117 11624 100 66     28874 if ( exists $args{message}
      66        
118             && (!ref($args{message}) || ref($args{message}) ne 'CODE') ) {
119 1         14 throw_exception( MessageParameterMustBeCodeRef => params => \%args,
120             class => $class
121             );
122             }
123              
124 11623         379259 my $self = $class->_new(%args);
125 11623 50       453088 $self->compile_type_constraint()
126             unless $self->_has_compiled_type_constraint;
127 11617 100       380550 $self->_default_message($_default_message_generator->($self->name))
128             unless $self->has_message;
129 11617         66579 return $self;
130             }
131              
132              
133              
134             sub coerce {
135 134     134 1 1079 my $self = shift;
136              
137 134         3478 my $coercion = $self->coercion;
138              
139 134 100       454 unless ($coercion) {
140 2         59 throw_exception( CoercingWithoutCoercions => type_name => $self->name );
141             }
142              
143 132 100       375 return $_[0] if $self->check($_[0]);
144              
145 117         1235 return $coercion->coerce(@_);
146             }
147              
148             sub assert_coerce {
149 3     3 1 2407 my $self = shift;
150              
151 3         9 my $result = $self->coerce(@_);
152              
153 3         13 $self->assert_valid($result);
154              
155 2         20 return $result;
156             }
157              
158             sub check {
159 9445     9445 1 173951 my ($self, @args) = @_;
160 9445         319920 my $constraint_subref = $self->_compiled_type_constraint;
161 9445 100       130319 return $constraint_subref->(@args) ? 1 : undef;
162             }
163              
164             sub validate {
165 18     18 1 464 my ($self, $value) = @_;
166 18 100       765 if ($self->_compiled_type_constraint->($value)) {
167 6         49 return undef;
168             }
169             else {
170 12         94 $self->get_message($value);
171             }
172             }
173              
174             sub can_be_inlined {
175 47670     47670 1 71626 my $self = shift;
176              
177 47670 100 100     1442064 if ( $self->has_parent && $self->constraint == $null_constraint ) {
178 1085         31115 return $self->parent->can_be_inlined;
179             }
180              
181 46585         1557308 return $self->_has_inlined_type_constraint;
182             }
183              
184             sub _inline_check {
185 24433     24433   40422 my $self = shift;
186              
187 24433 100       44416 unless ( $self->can_be_inlined ) {
188 2         56 throw_exception( CannotInlineTypeConstraintCheck => type_name => $self->name );
189             }
190              
191 24431 100 100     732460 if ( $self->has_parent && $self->constraint == $null_constraint ) {
192 511         15783 return $self->parent->_inline_check(@_);
193             }
194              
195 23920         656906 return '( do { ' . $self->inlined->( $self, @_ ) . ' } )';
196             }
197              
198             sub inline_environment {
199 21515     21515 1 40162 my $self = shift;
200              
201 21515 100 100     661639 if ( $self->has_parent && $self->constraint == $null_constraint ) {
202 495         15182 return $self->parent->inline_environment;
203             }
204              
205 21020         719283 return $self->_inline_environment;
206             }
207              
208             sub assert_valid {
209 8     8 1 898 my ( $self, $value ) = @_;
210              
211 8 100       31 return 1 if $self->check($value);
212              
213 3         43 throw_exception(
214             'ValidationFailedForTypeConstraint',
215             type => $self,
216             value => $value
217             );
218             }
219              
220             sub get_message {
221 926     926 1 1896 my ($self, $value) = @_;
222 926 100       25716 my $msg = $self->has_message
223             ? $self->message
224             : $self->_default_message;
225 926         1822 local $_ = $value;
226 926         2313 return $msg->($value);
227             }
228              
229             ## type predicates ...
230              
231             sub equals {
232 1765     1765 1 3987 my ( $self, $type_or_name ) = @_;
233              
234 1765         4275 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
235 1765 100       3556 return if not $other;
236              
237 1764 100       4144 return 1 if $self == $other;
238              
239 1357 100       38950 return unless $self->constraint == $other->constraint;
240              
241 1 50       37 if ( $self->has_parent ) {
242 0 0       0 return unless $other->has_parent;
243 0 0       0 return unless $self->parent->equals( $other->parent );
244             } else {
245 1 50       31 return if $other->has_parent;
246             }
247              
248 1         7 return;
249             }
250              
251             sub is_a_type_of {
252 265     265 1 1252 my ($self, $type_or_name) = @_;
253              
254 265         738 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
255 265 100       971 return if not $type;
256              
257 261 100       3498 ($self->equals($type) || $self->is_subtype_of($type));
258             }
259              
260             sub is_subtype_of {
261 579     579 1 2540 my ($self, $type_or_name) = @_;
262              
263 579         1635 my $type = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
264 579 100       1755 return if not $type;
265              
266 575         1129 my $current = $self;
267              
268 575         16029 while (my $parent = $current->parent) {
269 1602 100       3371 return 1 if $parent->equals($type);
270 1285         34202 $current = $parent;
271             }
272              
273 258         1295 return 0;
274             }
275              
276             ## compiling the type constraint
277              
278             sub compile_type_constraint {
279 14648     14648 0 25302 my $self = shift;
280 14648         34803 $self->_compiled_type_constraint($self->_actually_compile_type_constraint);
281             }
282              
283             ## type compilers ...
284              
285             sub _actually_compile_type_constraint {
286 14575     14575   21906 my $self = shift;
287              
288 14575 100       33668 if ( $self->can_be_inlined ) {
289 14458         40639 return eval_closure(
290             source => 'sub { ' . $self->_inline_check('$_[0]') . ' }',
291             environment => $self->inline_environment,
292             );
293             }
294              
295 117         3403 my $check = $self->constraint;
296 117 100       488 unless ( defined $check ) {
297 1         30 throw_exception( NoConstraintCheckForTypeConstraint => type_name => $self->name );
298             }
299              
300 116 100       3760 return $self->_compile_subtype($check)
301             if $self->has_parent;
302              
303 20         116 return $self->_compile_type($check);
304             }
305              
306             sub _compile_subtype {
307 125     125   444 my ($self, $check) = @_;
308              
309             # gather all the parent constraints in order
310 125         321 my @parents;
311 125         509 foreach my $parent ($self->_collect_all_parents) {
312 627         16155 push @parents => $parent->constraint;
313             }
314              
315 125         528 @parents = grep { $_ != $null_constraint } reverse @parents;
  627         1499  
316              
317 125 100       525 unless ( @parents ) {
318 2         5 return $self->_compile_type($check);
319             } else {
320             # general case, check all the constraints, from the first parent to ourselves
321 123         371 my @checks = @parents;
322 123 100       490 push @checks, $check if $check != $null_constraint;
323             return set_subname(
324             $self->name => sub {
325 1772     1772   248886 my (@args) = @_;
326 1772         3026 local $_ = $args[0];
327 1772         3716 foreach my $check (@checks) {
328 8098 100       18438 return undef unless $check->(@args);
329             }
330 1029         6672 return 1;
331             }
332 123         3595 );
333             }
334             }
335              
336             sub _compile_type {
337 48     48   151 my ($self, $check) = @_;
338              
339 48 100       525 return $check if $check == $null_constraint; # Item, Any
340              
341             return set_subname(
342             $self->name => sub {
343 756     756   8853 my (@args) = @_;
344 756         1262 local $_ = $args[0];
345 756         2201 $check->(@args);
346             }
347 39         999 );
348             }
349              
350             ## other utils ...
351              
352             sub _collect_all_parents {
353 138     138   320 my $self = shift;
354 138         266 my @parents;
355 138         3767 my $current = $self->parent;
356 138         584 while (defined $current) {
357 683         1309 push @parents => $current;
358 683         17125 $current = $current->parent;
359             }
360 138         724 return @parents;
361             }
362              
363             sub create_child_type {
364 6313     6313 1 22870 my ($self, %opts) = @_;
365 6313         13340 my $class = ref $self;
366 6313         21263 return $class->new(%opts, parent => $self);
367             }
368              
369             1;
370              
371             # ABSTRACT: The Moose Type Constraint metaclass
372              
373             __END__
374              
375             =pod
376              
377             =encoding UTF-8
378              
379             =head1 NAME
380              
381             Moose::Meta::TypeConstraint - The Moose Type Constraint metaclass
382              
383             =head1 VERSION
384              
385             version 2.2206
386              
387             =head1 DESCRIPTION
388              
389             This class represents a single type constraint. Moose's built-in type
390             constraints, as well as constraints you define, are all stored in a
391             L<Moose::Meta::TypeConstraint::Registry> object as objects of this
392             class.
393              
394             =head1 INHERITANCE
395              
396             C<Moose::Meta::TypeConstraint> is a subclass of L<Class::MOP::Object>.
397              
398             =head1 METHODS
399              
400             =head2 Moose::Meta::TypeConstraint->new(%options)
401              
402             This creates a new type constraint based on the provided C<%options>:
403              
404             =over 4
405              
406             =item * name
407              
408             The constraint name. If a name is not provided, it will be set to
409             "__ANON__".
410              
411             =item * parent
412              
413             A C<Moose::Meta::TypeConstraint> object which is the parent type for
414             the type being created. This is optional.
415              
416             =item * constraint
417              
418             This is the subroutine reference that implements the actual constraint
419             check. This defaults to a subroutine which always returns true.
420              
421             =item * message
422              
423             A subroutine reference which is used to generate an error message when
424             the constraint fails. This is optional.
425              
426             =item * coercion
427              
428             A L<Moose::Meta::TypeCoercion> object representing the coercions to
429             the type. This is optional.
430              
431             =item * inlined
432              
433             A subroutine which returns a string suitable for inlining this type
434             constraint. It will be called as a method on the type constraint object, and
435             will receive a single additional parameter, a variable name to be tested
436             (usually C<"$_"> or C<"$_[0]">.
437              
438             This is optional.
439              
440             =item * inline_environment
441              
442             A hash reference of variables to close over. The keys are variables names, and
443             the values are I<references> to the variables.
444              
445             =back
446              
447             =head2 $constraint->equals($type_name_or_object)
448              
449             Returns true if the supplied name or type object is the same as the
450             current type.
451              
452             =head2 $constraint->is_subtype_of($type_name_or_object)
453              
454             Returns true if the supplied name or type object is a parent of the
455             current type.
456              
457             =head2 $constraint->is_a_type_of($type_name_or_object)
458              
459             Returns true if the given type is the same as the current type, or is
460             a parent of the current type. This is a shortcut for checking
461             C<equals> and C<is_subtype_of>.
462              
463             =head2 $constraint->coerce($value)
464              
465             This will attempt to coerce the value to the type. If the type does not
466             have any defined coercions this will throw an error.
467              
468             If no coercion can produce a value matching C<$constraint>, the original
469             value is returned.
470              
471             =head2 $constraint->assert_coerce($value)
472              
473             This method behaves just like C<coerce>, but if the result is not valid
474             according to C<$constraint>, an error is thrown.
475              
476             =head2 $constraint->check($value)
477              
478             Returns true if the given value passes the constraint for the type.
479              
480             =head2 $constraint->validate($value)
481              
482             This is similar to C<check>. However, if the type I<is valid> then the
483             method returns an explicit C<undef>. If the type is not valid, we call
484             C<< $self->get_message($value) >> internally to generate an error
485             message.
486              
487             =head2 $constraint->assert_valid($value)
488              
489             Like C<check> and C<validate>, this method checks whether C<$value> is
490             valid under the constraint. If it is, it will return true. If it is not,
491             an exception will be thrown with the results of
492             C<< $self->get_message($value) >>.
493              
494             =head2 $constraint->name
495              
496             Returns the type's name, as provided to the constructor.
497              
498             =head2 $constraint->parent
499              
500             Returns the type's parent, as provided to the constructor, if any.
501              
502             =head2 $constraint->has_parent
503              
504             Returns true if the type has a parent type.
505              
506             =head2 $constraint->parents
507              
508             Returns all of the types parents as an list of type constraint objects.
509              
510             =head2 $constraint->constraint
511              
512             Returns the type's constraint, as provided to the constructor.
513              
514             =head2 $constraint->get_message($value)
515              
516             This generates a method for the given value. If the type does not have
517             an explicit message, we generate a default message.
518              
519             =head2 $constraint->has_message
520              
521             Returns true if the type has a message.
522              
523             =head2 $constraint->message
524              
525             Returns the type's message as a subroutine reference.
526              
527             =head2 $constraint->coercion
528              
529             Returns the type's L<Moose::Meta::TypeCoercion> object, if one
530             exists.
531              
532             =head2 $constraint->has_coercion
533              
534             Returns true if the type has a coercion.
535              
536             =head2 $constraint->can_be_inlined
537              
538             Returns true if this type constraint can be inlined. A type constraint which
539             subtypes an inlinable constraint and does not add an additional constraint
540             "inherits" its parent type's inlining.
541              
542             =head2 $constraint->create_child_type(%options)
543              
544             This returns a new type constraint of the same class using the
545             provided C<%options>. The C<parent> option will be the current type.
546              
547             This method exists so that subclasses of this class can override this
548             behavior and change how child types are created.
549              
550             =head1 BUGS
551              
552             See L<Moose/BUGS> for details on reporting bugs.
553              
554             =head1 AUTHORS
555              
556             =over 4
557              
558             =item *
559              
560             Stevan Little <stevan@cpan.org>
561              
562             =item *
563              
564             Dave Rolsky <autarch@urth.org>
565              
566             =item *
567              
568             Jesse Luehrs <doy@cpan.org>
569              
570             =item *
571              
572             Shawn M Moore <sartak@cpan.org>
573              
574             =item *
575              
576             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
577              
578             =item *
579              
580             Karen Etheridge <ether@cpan.org>
581              
582             =item *
583              
584             Florian Ragwitz <rafl@debian.org>
585              
586             =item *
587              
588             Hans Dieter Pearcey <hdp@cpan.org>
589              
590             =item *
591              
592             Chris Prather <chris@prather.org>
593              
594             =item *
595              
596             Matt S Trout <mstrout@cpan.org>
597              
598             =back
599              
600             =head1 COPYRIGHT AND LICENSE
601              
602             This software is copyright (c) 2006 by Infinity Interactive, Inc.
603              
604             This is free software; you can redistribute it and/or modify it under
605             the same terms as the Perl 5 programming language system itself.
606              
607             =cut