2 package Moose::Util::TypeConstraints;
8 use Scalar::Util 'blessed', 'reftype';
12 our $VERSION = '0.14';
13 our $AUTHORITY = 'cpan:STEVAN';
15 # Prototyped subs must be predeclared because we have a circular dependency
16 # with Moose::Meta::Attribute et. al. so in case of us being use'd first the
17 # predeclaration ensures the prototypes are in scope when consumers are
20 sub find_type_constraint ($);
21 sub _create_type_constraint ($$$;$$);
22 sub _install_type_coercions ($$);
23 sub create_type_constraint_union (@);
35 use Moose::Meta::TypeConstraint;
36 use Moose::Meta::TypeConstraint::Union;
37 use Moose::Meta::TypeConstraint::Container;
38 use Moose::Meta::TypeCoercion;
39 use Moose::Meta::TypeCoercion::Union;
40 use Moose::Meta::TypeConstraint::Registry;
43 type subtype as where message optimize_as
49 Sub::Exporter::setup_exporter({
51 groups => { default => [':all'] }
57 # loop through the exports ...
58 foreach my $name (@exports) {
60 if (defined &{$class . '::' . $name}) {
61 my $keyword = \&{$class . '::' . $name};
63 # make sure it is from Moose
64 my $pkg_name = eval { svref_2object($keyword)->GV->STASH->NAME };
66 next if $pkg_name ne 'Moose::Util::TypeConstraints';
68 # and if it is from Moose then undef the slot
69 delete ${$class . '::'}{$name};
74 my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new;
76 sub _get_type_constraint_registry { $REGISTRY }
77 sub _dump_type_constraints { $REGISTRY->dump }
80 # this method breaks down the sugar
81 # from the functions below.
82 sub _create_type_constraint ($$$;$$) {
85 my $check = shift || sub { 1 };
87 my ($message, $optimized);
89 $message = $_->{message} if exists $_->{message};
90 $optimized = $_->{optimized} if exists $_->{optimized};
93 my $pkg_defined_in = scalar(caller(0));
96 my $type = $REGISTRY->get_type_constraint($name);
98 ($type->_package_defined_in eq $pkg_defined_in)
99 || confess ("The type constraint '$name' has already been created in "
100 . $type->_package_defined_in . " and cannot be created again in "
105 $parent = $REGISTRY->get_type_constraint($parent) if defined $parent;
107 my $constraint = Moose::Meta::TypeConstraint->new(
108 name => $name || '__ANON__',
110 constraint => $check,
112 optimized => $optimized,
113 package_defined_in => $pkg_defined_in,
116 $REGISTRY->add_type_constraint($constraint)
122 sub _install_type_coercions ($$) {
123 my ($type_name, $coercion_map) = @_;
124 my $type = $REGISTRY->get_type_constraint($type_name);
125 (!$type->has_coercion)
126 || confess "The type coercion for '$type_name' has already been registered";
127 my $type_coercion = Moose::Meta::TypeCoercion->new(
128 type_coercion_map => $coercion_map,
129 type_constraint => $type
131 $type->coercion($type_coercion);
134 sub create_type_constraint_union (@) {
135 my (@type_constraint_names) = @_;
136 (scalar @type_constraint_names >= 2)
137 || confess "You must pass in at least 2 type names to make a union";
138 return Moose::Meta::TypeConstraint::Union->new(
139 type_constraints => [
141 $REGISTRY->get_type_constraint($_)
142 } @type_constraint_names
147 sub export_type_constraints_as_functions {
150 foreach my $constraint (keys %{$REGISTRY->type_constraints}) {
151 *{"${pkg}::${constraint}"} = $REGISTRY->get_type_constraint($constraint)
152 ->_compiled_type_constraint;
156 *Moose::Util::TypeConstraints::export_type_contstraints_as_functions = \&export_type_constraints_as_functions;
158 sub list_all_type_constraints { keys %{$REGISTRY->type_constraints} }
160 ## --------------------------------------------------------
161 ## exported functions ...
162 ## --------------------------------------------------------
164 sub find_type_constraint ($) { $REGISTRY->get_type_constraint(@_) }
169 splice(@_, 1, 0, undef);
170 goto &_create_type_constraint;
173 sub subtype ($$;$$$) {
175 # this adds an undef for the name
176 # if this is an anon-subtype:
177 # subtype(Num => where { $_ % 2 == 0 }) # anon 'even' subtype
178 # but if the last arg is not a code
179 # ref then it is a subtype alias:
180 # subtype(MyNumbers => as Num); # now MyNumbers is the same as Num
181 # ... yeah I know it's ugly code
183 unshift @_ => undef if scalar @_ <= 2 && (reftype($_[1]) || '') eq 'CODE';
184 goto &_create_type_constraint;
188 my ($type_name, @coercion_map) = @_;
189 _install_type_coercions($type_name, \@coercion_map);
193 sub from ($) { $_[0] }
194 sub where (&) { $_[0] }
195 sub via (&) { $_[0] }
197 sub message (&) { +{ message => $_[0] } }
198 sub optimize_as (&) { +{ optimized => $_[0] } }
201 my ($type_name, @values) = @_;
202 (scalar @values >= 2)
203 || confess "You must have at least two values to enumerate through";
204 my $regexp = join '|' => @values;
205 _create_type_constraint(
208 sub { qr/^$regexp$/i }
212 # define some basic types
214 type 'Any' => where { 1 }; # meta-type including all
215 type 'Item' => where { 1 }; # base-type
217 subtype 'Undef' => as 'Item' => where { !defined($_) };
218 subtype 'Defined' => as 'Item' => where { defined($_) };
222 => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
226 => where { !ref($_) }
227 => optimize_as { defined($_[0]) && !ref($_[0]) };
232 => optimize_as { ref($_[0]) };
237 => optimize_as { defined($_[0]) && !ref($_[0]) };
241 => where { Scalar::Util::looks_like_number($_) }
242 => optimize_as { !ref($_[0]) && Scalar::Util::looks_like_number($_[0]) };
246 => where { "$_" =~ /^-?[0-9]+$/ }
247 => optimize_as { defined($_[0]) && !ref($_[0]) && $_[0] =~ /^-?[0-9]+$/ };
249 subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } => optimize_as { ref($_[0]) eq 'SCALAR' };
250 subtype 'ArrayRef' => as 'Ref' => where { ref($_) eq 'ARRAY' } => optimize_as { ref($_[0]) eq 'ARRAY' };
251 subtype 'HashRef' => as 'Ref' => where { ref($_) eq 'HASH' } => optimize_as { ref($_[0]) eq 'HASH' };
252 subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } => optimize_as { ref($_[0]) eq 'CODE' };
253 subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } => optimize_as { ref($_[0]) eq 'Regexp' };
254 subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } => optimize_as { ref($_[0]) eq 'GLOB' };
257 # scalar filehandles are GLOB refs,
258 # but a GLOB ref is not always a filehandle
261 => where { Scalar::Util::openhandle($_) }
262 => optimize_as { ref($_[0]) eq 'GLOB' && Scalar::Util::openhandle($_[0]) };
265 # blessed(qr/.../) returns true,.. how odd
268 => where { blessed($_) && blessed($_) ne 'Regexp' }
269 => optimize_as { blessed($_[0]) && blessed($_[0]) ne 'Regexp' };
273 => where { $_->can('does') }
274 => optimize_as { blessed($_[0]) && $_[0]->can('does') };
278 => where { eval { $_->isa('UNIVERSAL') } }
279 => optimize_as { !ref($_[0]) && eval { $_[0]->isa('UNIVERSAL') } };
282 my @BUILTINS = list_all_type_constraints();
283 sub list_all_builtin_type_constraints { @BUILTINS }
294 Moose::Util::TypeConstraints - Type constraint system for Moose
298 use Moose::Util::TypeConstraints;
300 type 'Num' => where { Scalar::Util::looks_like_number($_) };
306 subtype 'NaturalLessThanTen'
309 => message { "This number ($_) is not less than ten!" };
315 enum 'RGBColors' => qw(red green blue);
319 This module provides Moose with the ability to create custom type
320 contraints to be used in attribute definition.
322 =head2 Important Caveat
324 This is B<NOT> a type system for Perl 5. These are type constraints,
325 and they are not used by Moose unless you tell it to. No type
326 inference is performed, expression are not typed, etc. etc. etc.
328 This is simply a means of creating small constraint functions which
329 can be used to simplify your own type-checking code.
331 =head2 Slightly Less Important Caveat
333 It is almost always a good idea to quote your type and subtype names.
334 This is to prevent perl from trying to execute the call as an indirect
335 object call. This issue only seems to come up when you have a subtype
336 the same name as a valid class, but when the issue does arise it tends
337 to be quite annoying to debug.
339 So for instance, this:
341 subtype DateTime => as Object => where { $_->isa('DateTime') };
343 will I<Just Work>, while this:
346 subtype DateTime => as Object => where { $_->isa('DateTime') };
348 will fail silently and cause many headaches. The simple way to solve
349 this, as well as future proof your subtypes from classes which have
350 yet to have been created yet, is to simply do this:
353 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
355 =head2 Default Type Constraints
357 This module also provides a simple hierarchy for Perl 5 types, this
358 could probably use some work, but it works for me at the moment.
381 Suggestions for improvement are welcome.
383 B<NOTE:> The C<Undef> type constraint does not work correctly
384 in every occasion, please use it sparringly.
386 B<NOTE:> The C<ClassName> type constraint is simply a subtype
387 of string which responds true to C<isa('UNIVERSAL')>. This means
388 that your class B<must> be loaded for this type constraint to
389 pass. I know this is not ideal for all, but it is a saner
390 restriction than most others.
392 =head2 Use with Other Constraint Modules
394 This module should play fairly nicely with other constraint
395 modules with only some slight tweaking. The C<where> clause
396 in types is expected to be a C<CODE> reference which checks
397 it's first argument and returns a bool. Since most constraint
398 modules work in a similar way, it should be simple to adapt
399 them to work with Moose.
401 For instance, this is how you could use it with
402 L<Declare::Constraints::Simple> to declare a completely new type.
404 type 'HashOfArrayOfObjects'
407 -values => IsArrayRef( IsObject ));
409 For more examples see the F<t/204_example_w_DCS.t> test file.
411 Here is an example of using L<Test::Deep> and it's non-test
412 related C<eq_deeply> function.
414 type 'ArrayOfHashOfBarsAndRandomNumbers'
417 array_each(subhashof({
419 random_number => ignore()
423 For a complete example see the F<t/205_example_w_TestDeep.t>
428 =head2 Type Constraint Registry
432 =item B<find_type_constraint ($type_name)>
434 This function can be used to locate a specific type constraint
435 meta-object, of the class L<Moose::Meta::TypeConstraint> or a
436 derivative. What you do with it from there is up to you :)
438 =item B<create_type_constraint_union (@type_constraint_names)>
440 Given a list of C<@type_constraint_names>, this will return a
441 B<Moose::Meta::TypeConstraint::Union> instance.
443 =item B<export_type_constraints_as_functions>
445 This will export all the current type constraints as functions
446 into the caller's namespace. Right now, this is mostly used for
447 testing, but it might prove useful to others.
449 =item B<export_type_contstraints_as_functions>
451 Alias for the above function.
453 =item B<list_all_type_constraints>
455 This will return a list of type constraint names, you can then
456 fetch them using C<find_type_constraint ($type_name)> if you
459 =item B<list_all_builtin_type_constraints>
461 This will return a list of builtin type constraints, meaning,
462 those which are defined in this module. See the section
463 labeled L<Default Type Constraints> for a complete list.
467 =head2 Type Constraint Constructors
469 The following functions are used to create type constraints.
470 They will then register the type constraints in a global store
471 where Moose can get to them if it needs to.
473 See the L<SYNOPSIS> for an example of how to use these.
477 =item B<type ($name, $where_clause)>
479 This creates a base type, which has no parent.
481 =item B<subtype ($name, $parent, $where_clause, ?$message)>
483 This creates a named subtype.
485 =item B<subtype ($parent, $where_clause, ?$message)>
487 This creates an unnamed subtype and will return the type
488 constraint meta-object, which will be an instance of
489 L<Moose::Meta::TypeConstraint>.
491 =item B<enum ($name, @values)>
493 This will create a basic subtype for a given set of strings.
494 The resulting constraint will be a subtype of C<Str> and
495 will match any of the items in C<@values>. See the L<SYNOPSIS>
496 for a simple example.
498 B<NOTE:> This is not a true proper enum type, it is simple
499 a convient constraint builder.
503 This is just sugar for the type constraint construction syntax.
507 This is just sugar for the type constraint construction syntax.
511 This is just sugar for the type constraint construction syntax.
515 This can be used to define a "hand optimized" version of your
516 type constraint which can be used to avoid traversing a subtype
517 constraint heirarchy.
519 B<NOTE:> You should only use this if you know what you are doing,
520 all the built in types use this, so your subtypes (assuming they
521 are shallow) will not likely need to use this.
525 =head2 Type Coercion Constructors
527 Type constraints can also contain type coercions as well. If you
528 ask your accessor to coerce, then Moose will run the type-coercion
529 code first, followed by the type constraint check. This feature
530 should be used carefully as it is very powerful and could easily
531 take off a limb if you are not careful.
533 See the L<SYNOPSIS> for an example of how to use these.
541 This is just sugar for the type coercion construction syntax.
545 This is just sugar for the type coercion construction syntax.
549 =head2 Namespace Management
555 This will remove all the type constraint keywords from the
556 calling class namespace.
562 All complex software has bugs lurking in it, and this module is no
563 exception. If you find a bug please either email me, or add the bug
568 Stevan Little E<lt>stevan@iinteractive.comE<gt>
570 =head1 COPYRIGHT AND LICENSE
572 Copyright 2006, 2007 by Infinity Interactive, Inc.
574 L<http://www.iinteractive.com>
576 This library is free software; you can redistribute it and/or modify
577 it under the same terms as Perl itself.