1 package Mouse::Util::TypeConstraints;
2 use Mouse::Util; # enables strict and warnings
7 use Mouse::Meta::TypeConstraint;
10 Mouse::Exporter->setup_import_methods(
12 as where message optimize_as
15 type subtype class_type role_type duck_type
20 register_type_constraint
24 our @CARP_NOT = qw(Mouse::Meta::Attribute);
29 $TYPE{Any} = Mouse::Meta::TypeConstraint->new(
34 # $name => $parent, $code,
40 Maybe => 'Item', undef,
43 Undef => 'Item', \&Undef,
44 Defined => 'Item', \&Defined,
45 Bool => 'Item', \&Bool,
46 Value => 'Defined', \&Value,
47 Str => 'Value', \&Str,
52 Ref => 'Defined', \&Ref,
53 ScalarRef => 'Ref', \&ScalarRef,
54 ArrayRef => 'Ref', \&ArrayRef,
55 HashRef => 'Ref', \&HashRef,
56 CodeRef => 'Ref', \&CodeRef,
57 RegexpRef => 'Ref', \&RegexpRef,
58 GlobRef => 'Ref', \&GlobRef,
61 FileHandle => 'GlobRef', \&FileHandle,
62 Object => 'Ref', \&Object,
64 # special string types
65 ClassName => 'Str', \&ClassName,
66 RoleName => 'ClassName', \&RoleName,
70 while (my ($name, $parent, $code) = splice @builtins, 0, 3) {
71 $TYPE{$name} = Mouse::Meta::TypeConstraint->new(
73 parent => $TYPE{$parent},
78 # make it parametarizable
80 $TYPE{Maybe} {constraint_generator} = \&_parameterize_Maybe_for;
81 $TYPE{ArrayRef}{constraint_generator} = \&_parameterize_ArrayRef_for;
82 $TYPE{HashRef} {constraint_generator} = \&_parameterize_HashRef_for;
86 sub as ($) { (as => $_[0]) } ## no critic
87 sub where (&) { (where => $_[0]) } ## no critic
88 sub message (&) { (message => $_[0]) } ## no critic
89 sub optimize_as (&) { (optimize_as => $_[0]) } ## no critic
92 sub via (&) { $_[0] } ## no critic
96 sub optimized_constraints { # DEPRECATED
97 Carp::cluck('optimized_constraints() has been deprecated');
101 undef @builtins; # free the allocated memory
102 @builtins = keys %TYPE; # reuse it
103 sub list_all_builtin_type_constraints { @builtins }
105 sub list_all_type_constraints { keys %TYPE }
113 if(@_ == 1 && ref $_[0]){ # @_ : { name => $name, where => ... }
116 elsif(@_ == 2 && ref $_[1]){ # @_ : $name => { where => ... }
120 elsif(@_ % 2){ # @_ : $name => ( where => ... )
123 else{ # @_ : (name => $name, where => ...)
133 if($mode eq 'subtype'){
134 $parent = delete $args{as};
136 $parent = delete $args{name};
142 # set 'package_defined_in' only if it is not a core package
143 my $this = $args{package_defined_in};
146 if($this !~ /\A Mouse \b/xms){
147 $args{package_defined_in} = $this;
152 my $that = $TYPE{$name}->{package_defined_in} || __PACKAGE__;
155 if($that eq __PACKAGE__) {
156 $note = sprintf " ('%s' is %s type constraint)",
158 scalar(grep { $name eq $_ } list_all_builtin_type_constraints())
160 : 'an implicitly created';
162 Carp::croak("The type constraint '$name' has already been created in $that"
163 . " and cannot be created again in $this" . $note);
168 $args{name} = '__ANON__';
171 $args{constraint} = delete $args{where} if exists $args{where};
172 $args{optimized} = delete $args{optimized_as} if exists $args{optimized_as};
175 if($mode eq 'subtype'){
176 $constraint = find_or_create_isa_type_constraint($parent)->create_child_type(%args);
179 $constraint = Mouse::Meta::TypeConstraint->new(%args);
183 return $TYPE{$name} = $constraint;
191 return _create_type('type', @_);
195 return _create_type('subtype', @_);
199 my $type_name = shift;
201 my $type = find_type_constraint($type_name)
202 or Carp::croak("Cannot find type '$type_name', perhaps you forgot to load it.");
204 $type->_add_type_coercions(@_);
209 my($name, $options) = @_;
210 my $class = $options->{class} || $name;
213 return _create_type 'subtype', $name => (
215 optimized_as => Mouse::Util::generate_isa_predicate_for($class),
220 my($name, $options) = @_;
221 my $role = $options->{role} || $name;
224 return _create_type 'subtype', $name => (
226 optimized_as => sub {
227 return Scalar::Util::blessed($_[0])
228 && Mouse::Util::does_role($_[0], $role);
236 if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){
240 @methods = (@_ == 1 && ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_;
243 return _create_type 'subtype', $name => (
245 optimized_as => Mouse::Util::generate_can_predicate_for(\@methods),
252 if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){
256 %valid = map{ $_ => undef }
257 (@_ == 1 && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_);
260 return _create_type 'subtype', $name => (
263 return defined($_[0]) && !ref($_[0]) && exists $valid{$_[0]};
268 sub _find_or_create_regular_type{
269 my($spec, $create) = @_;
271 return $TYPE{$spec} if exists $TYPE{$spec};
273 my $meta = Mouse::Util::get_metaclass_by_name($spec);
276 return $create ? class_type($spec) : undef;
279 if(Mouse::Util::is_a_metarole($meta)){
280 return role_type($spec);
283 return class_type($spec);
287 sub _find_or_create_parameterized_type{
288 my($base, $param) = @_;
290 my $name = sprintf '%s[%s]', $base->name, $param->name;
292 $TYPE{$name} ||= $base->parameterize($param, $name);
295 sub _find_or_create_union_type{
296 return if grep{ not defined } @_;
297 my @types = sort map{ $_->{type_constraints} ? @{$_->{type_constraints}} : $_ } @_;
299 my $name = join '|', @types;
302 $TYPE{$name} ||= Mouse::Meta::TypeConstraint->new(
304 type_constraints => \@types,
310 # param : '[' type ']' | NOTHING
314 if($c->{spec} =~ s/^\[//){
315 my $type = _parse_type($c, 1);
317 if($c->{spec} =~ s/^\]//){
320 Carp::croak("Syntax error in type: missing right square bracket in '$c->{orig}'");
328 my($c, $create) = @_;
330 if($c->{spec} =~ s/\A ([\w.:]+) //xms){
331 return _find_or_create_regular_type($1, $create);
333 Carp::croak("Syntax error in type: expect type name near '$c->{spec}' in '$c->{orig}'");
336 # single_type : name param
337 sub _parse_single_type {
338 my($c, $create) = @_;
340 my $type = _parse_name($c, $create);
341 my $param = _parse_param($c);
345 return _find_or_create_parameterized_type($type, $param);
351 elsif(defined $param){
352 Carp::croak("Undefined type with parameter [$param] in '$c->{orig}'");
359 # type : single_type ('|' single_type)*
361 my($c, $create) = @_;
363 my $type = _parse_single_type($c, $create);
364 if($c->{spec}){ # can be an union type
366 while($c->{spec} =~ s/^\|//){
367 push @types, _parse_single_type($c, $create);
370 return _find_or_create_union_type($type, @types);
377 sub find_type_constraint {
379 return $spec if Mouse::Util::is_a_type_constraint($spec) or not defined $spec;
385 sub register_type_constraint {
386 my($constraint) = @_;
387 Carp::croak("No type supplied / type is not a valid type constraint")
388 unless Mouse::Util::is_a_type_constraint($constraint);
389 my $name = $constraint->name;
390 Carp::croak("can't register an unnamed type constraint")
391 unless defined $name;
392 return $TYPE{$name} = $constraint;
395 sub find_or_parse_type_constraint {
397 return $spec if Mouse::Util::is_a_type_constraint($spec) or not defined $spec;
400 return $TYPE{$spec} || do{
405 my $type = _parse_type($context);
407 if($context->{spec}){
408 Carp::croak("Syntax error: extra elements '$context->{spec}' in '$context->{orig}'");
414 sub find_or_create_does_type_constraint{
415 # XXX: Moose does not register a new role_type, but Mouse does.
416 return find_or_parse_type_constraint(@_) || role_type(@_);
419 sub find_or_create_isa_type_constraint {
420 # XXX: Moose does not register a new class_type, but Mouse does.
421 return find_or_parse_type_constraint(@_) || class_type(@_);
429 Mouse::Util::TypeConstraints - Type constraint system for Mouse
433 This document describes Mouse version 0.70
437 use Mouse::Util::TypeConstraints;
443 subtype 'NaturalLessThanTen'
446 => message { "This number ($_) is not less than ten!" };
452 enum 'RGBColors' => qw(red green blue);
454 no Mouse::Util::TypeConstraints;
458 This module provides Mouse with the ability to create custom type
459 constraints to be used in attribute definition.
461 =head2 Important Caveat
463 This is B<NOT> a type system for Perl 5. These are type constraints,
464 and they are not used by Mouse unless you tell it to. No type
465 inference is performed, expressions are not typed, etc. etc. etc.
467 A type constraint is at heart a small "check if a value is valid"
468 function. A constraint can be associated with an attribute. This
469 simplifies parameter validation, and makes your code clearer to read,
470 because you can refer to constraints by name.
472 =head2 Slightly Less Important Caveat
474 It is B<always> a good idea to quote your type names.
476 This prevents Perl from trying to execute the call as an indirect
477 object call. This can be an issue when you have a subtype with the
478 same name as a valid class.
482 subtype DateTime => as Object => where { $_->isa('DateTime') };
484 will I<just work>, while this:
487 subtype DateTime => as Object => where { $_->isa('DateTime') };
489 will fail silently and cause many headaches. The simple way to solve
490 this, as well as future proof your subtypes from classes which have
491 yet to have been created, is to quote the type name:
494 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
496 =head2 Default Type Constraints
498 This module also provides a simple hierarchy for Perl 5 types, here is
499 that hierarchy represented visually.
523 B<NOTE:> Any type followed by a type parameter C<[`a]> can be
524 parameterized, this means you can say:
526 ArrayRef[Int] # an array of integers
527 HashRef[CodeRef] # a hash of str to CODE ref mappings
528 Maybe[Str] # value may be a string, may be undefined
530 If Mouse finds a name in brackets that it does not recognize as an
531 existing type, it assumes that this is a class name, for example
532 C<ArrayRef[DateTime]>.
534 B<NOTE:> The C<Undef> type constraint for the most part works
535 correctly now, but edge cases may still exist, please use it
538 B<NOTE:> The C<ClassName> type constraint does a complex package
539 existence check. This means that your class B<must> be loaded for this
540 type constraint to pass.
542 B<NOTE:> The C<RoleName> constraint checks a string is a I<package
543 name> which is a role, like C<'MyApp::Role::Comparable'>. The C<Role>
544 constraint checks that an I<object does> the named role.
546 =head2 Type Constraint Naming
548 Type name declared via this module can only contain alphanumeric
549 characters, colons (:), and periods (.).
551 Since the types created by this module are global, it is suggested
552 that you namespace your types just as you would namespace your
553 modules. So instead of creating a I<Color> type for your
554 B<My::Graphics> module, you would call the type
555 I<My::Graphics::Types::Color> instead.
557 =head2 Use with Other Constraint Modules
559 This module can play nicely with other constraint modules with some
560 slight tweaking. The C<where> clause in types is expected to be a
561 C<CODE> reference which checks it's first argument and returns a
562 boolean. Since most constraint modules work in a similar way, it
563 should be simple to adapt them to work with Mouse.
565 For instance, this is how you could use it with
566 L<Declare::Constraints::Simple> to declare a completely new type.
568 type 'HashOfArrayOfObjects',
572 -values => IsArrayRef(IsObject)
576 Here is an example of using L<Test::Deep> and it's non-test
577 related C<eq_deeply> function.
579 type 'ArrayOfHashOfBarsAndRandomNumbers'
582 array_each(subhashof({
584 random_number => ignore()
590 =head2 C<< list_all_builtin_type_constraints -> (Names) >>
592 Returns the names of builtin type constraints.
594 =head2 C<< list_all_type_constraints -> (Names) >>
596 Returns the names of all the type constraints.
602 =item C<< type $name => where { } ... -> Mouse::Meta::TypeConstraint >>
604 =item C<< subtype $name => as $parent => where { } ... -> Mouse::Meta::TypeConstraint >>
606 =item C<< subtype as $parent => where { } ... -> Mouse::Meta::TypeConstraint >>
608 =item C<< class_type ($class, ?$options) -> Mouse::Meta::TypeConstraint >>
610 =item C<< role_type ($role, ?$options) -> Mouse::Meta::TypeConstraint >>
612 =item C<< duck_type($name, @methods | \@methods) -> Mouse::Meta::TypeConstraint >>
614 =item C<< duck_type(\@methods) -> Mouse::Meta::TypeConstraint >>
616 =item C<< enum($name, @values | \@values) -> Mouse::Meta::TypeConstraint >>
618 =item C<< enum (\@values) -> Mouse::Meta::TypeConstraint >>
620 =item C<< coerce $type => from $another_type, via { }, ... >>
626 =item C<< find_type_constraint(Type) -> Mouse::Meta::TypeConstraint >>
632 Much of this documentation was taken from C<Moose::Util::TypeConstraints>
636 L<Moose::Util::TypeConstraints>