2 package Moose::Util::TypeConstraints;
8 use Scalar::Util 'blessed';
12 our $VERSION = '0.12';
13 our $AUTHORITY = 'cpan:STEVAN';
15 use Moose::Meta::TypeConstraint;
16 use Moose::Meta::TypeCoercion;
19 type subtype as where message optimize_as
25 Sub::Exporter::setup_exporter({
27 groups => { default => [':all'] }
33 # loop through the exports ...
34 foreach my $name (@exports) {
36 if (defined &{$class . '::' . $name}) {
37 my $keyword = \&{$class . '::' . $name};
39 # make sure it is from Moose
40 my $pkg_name = eval { svref_2object($keyword)->GV->STASH->NAME };
42 next if $pkg_name ne 'Moose::Util::TypeConstraints';
44 # and if it is from Moose then undef the slot
45 delete ${$class . '::'}{$name};
52 sub find_type_constraint ($) {
53 return $TYPES{$_[0]}->[1]
54 if exists $TYPES{$_[0]};
58 sub _dump_type_constraints {
60 Data::Dumper::Dumper(\%TYPES);
63 sub _create_type_constraint ($$$;$$) {
68 my ($message, $optimized);
70 $message = $_->{message} if exists $_->{message};
71 $optimized = $_->{optimized} if exists $_->{optimized};
74 my $pkg_defined_in = scalar(caller(0));
76 ($TYPES{$name}->[0] eq $pkg_defined_in)
77 || confess ("The type constraint '$name' has already been created in "
78 . $TYPES{$name}->[0] . " and cannot be created again in "
80 if defined $name && exists $TYPES{$name};
82 $parent = find_type_constraint($parent) if defined $parent;
83 my $constraint = Moose::Meta::TypeConstraint->new(
84 name => $name || '__ANON__',
88 optimized => $optimized,
90 $TYPES{$name} = [ $pkg_defined_in, $constraint ] if defined $name;
94 sub _install_type_coercions ($$) {
95 my ($type_name, $coercion_map) = @_;
96 my $type = find_type_constraint($type_name);
97 (!$type->has_coercion)
98 || confess "The type coercion for '$type_name' has already been registered";
99 my $type_coercion = Moose::Meta::TypeCoercion->new(
100 type_coercion_map => $coercion_map,
101 type_constraint => $type
103 $type->coercion($type_coercion);
106 sub create_type_constraint_union (@) {
107 my (@type_constraint_names) = @_;
108 return Moose::Meta::TypeConstraint->union(
110 find_type_constraint($_)
111 } @type_constraint_names
115 sub export_type_contstraints_as_functions {
118 foreach my $constraint (keys %TYPES) {
119 *{"${pkg}::${constraint}"} = find_type_constraint($constraint)->_compiled_type_constraint;
123 sub list_all_type_constraints { keys %TYPES }
129 splice(@_, 1, 0, undef);
130 goto &_create_type_constraint;
133 sub subtype ($$;$$$) {
134 unshift @_ => undef if scalar @_ <= 2;
135 goto &_create_type_constraint;
139 my ($type_name, @coercion_map) = @_;
140 _install_type_coercions($type_name, \@coercion_map);
144 sub from ($) { $_[0] }
145 sub where (&) { $_[0] }
146 sub via (&) { $_[0] }
148 sub message (&) { +{ message => $_[0] } }
149 sub optimize_as (&) { +{ optimized => $_[0] } }
152 my ($type_name, @values) = @_;
153 (scalar @values >= 2)
154 || confess "You must have at least two values to enumerate through";
155 my $regexp = join '|' => @values;
156 _create_type_constraint(
159 sub { qr/^$regexp$/i }
163 # define some basic types
165 type 'Any' => where { 1 }; # meta-type including all
166 type 'Item' => where { 1 }; # base-type
168 subtype 'Undef' => as 'Item' => where { !defined($_) };
169 subtype 'Defined' => as 'Item' => where { defined($_) };
173 => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
177 => where { !ref($_) }
178 => optimize_as { defined($_[0]) && !ref($_[0]) };
183 => optimize_as { ref($_[0]) };
188 => optimize_as { defined($_[0]) && !ref($_[0]) };
192 => where { Scalar::Util::looks_like_number($_) }
193 => optimize_as { !ref($_[0]) && Scalar::Util::looks_like_number($_[0]) };
197 => where { "$_" =~ /^-?[0-9]+$/ }
198 => optimize_as { defined($_[0]) && !ref($_[0]) && $_[0] =~ /^-?[0-9]+$/ };
200 subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } => optimize_as { ref($_[0]) eq 'SCALAR' };
201 subtype 'ArrayRef' => as 'Ref' => where { ref($_) eq 'ARRAY' } => optimize_as { ref($_[0]) eq 'ARRAY' };
202 subtype 'HashRef' => as 'Ref' => where { ref($_) eq 'HASH' } => optimize_as { ref($_[0]) eq 'HASH' };
203 subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } => optimize_as { ref($_[0]) eq 'CODE' };
204 subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } => optimize_as { ref($_[0]) eq 'Regexp' };
205 subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } => optimize_as { ref($_[0]) eq 'GLOB' };
208 # scalar filehandles are GLOB refs,
209 # but a GLOB ref is not always a filehandle
212 => where { Scalar::Util::openhandle($_) }
213 => optimize_as { ref($_[0]) eq 'GLOB' && Scalar::Util::openhandle($_[0]) };
216 # blessed(qr/.../) returns true,.. how odd
219 => where { blessed($_) && blessed($_) ne 'Regexp' }
220 => optimize_as { blessed($_[0]) && blessed($_[0]) ne 'Regexp' };
224 => where { $_->can('does') }
225 => optimize_as { blessed($_[0]) && $_[0]->can('does') };
228 my @BUILTINS = list_all_type_constraints();
229 sub list_all_builtin_type_constraints { @BUILTINS }
240 Moose::Util::TypeConstraints - Type constraint system for Moose
244 use Moose::Util::TypeConstraints;
246 type 'Num' => where { Scalar::Util::looks_like_number($_) };
252 subtype 'NaturalLessThanTen'
255 => message { "This number ($_) is not less than ten!" };
261 enum 'RGBColors' => qw(red green blue);
265 This module provides Moose with the ability to create custom type
266 contraints to be used in attribute definition.
268 =head2 Important Caveat
270 This is B<NOT> a type system for Perl 5. These are type constraints,
271 and they are not used by Moose unless you tell it to. No type
272 inference is performed, expression are not typed, etc. etc. etc.
274 This is simply a means of creating small constraint functions which
275 can be used to simplify your own type-checking code.
277 =head2 Slightly Less Important Caveat
279 It is almost always a good idea to quote your type and subtype names.
280 This is to prevent perl from trying to execute the call as an indirect
281 object call. This issue only seems to come up when you have a subtype
282 the same name as a valid class, but when the issue does arise it tends
283 to be quite annoying to debug.
285 So for instance, this:
287 subtype DateTime => as Object => where { $_->isa('DateTime') };
289 will I<Just Work>, while this:
292 subtype DateTime => as Object => where { $_->isa('DateTime') };
294 will fail silently and cause many headaches. The simple way to solve
295 this, as well as future proof your subtypes from classes which have
296 yet to have been created yet, is to simply do this:
299 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
301 =head2 Default Type Constraints
303 This module also provides a simple hierarchy for Perl 5 types, this
304 could probably use some work, but it works for me at the moment.
326 Suggestions for improvement are welcome.
328 B<NOTE:> The C<Undef> type constraint does not work correctly
329 in every occasion, please use it sparringly.
331 =head2 Use with Other Constraint Modules
333 This module should play fairly nicely with other constraint
334 modules with only some slight tweaking. The C<where> clause
335 in types is expected to be a C<CODE> reference which checks
336 it's first argument and returns a bool. Since most constraint
337 modules work in a similar way, it should be simple to adapt
338 them to work with Moose.
340 For instance, this is how you could use it with
341 L<Declare::Constraints::Simple> to declare a completely new type.
343 type 'HashOfArrayOfObjects'
346 -values => IsArrayRef( IsObject ));
348 For more examples see the F<t/204_example_w_DCS.t> test file.
350 Here is an example of using L<Test::Deep> and it's non-test
351 related C<eq_deeply> function.
353 type 'ArrayOfHashOfBarsAndRandomNumbers'
356 array_each(subhashof({
358 random_number => ignore()
362 For a complete example see the F<t/205_example_w_TestDeep.t>
367 =head2 Type Constraint Registry
371 =item B<find_type_constraint ($type_name)>
373 This function can be used to locate a specific type constraint
374 meta-object. What you do with it from there is up to you :)
376 =item B<create_type_constraint_union (@type_constraint_names)>
378 Given a list of C<@type_constraint_names>, this will return a
379 B<Moose::Meta::TypeConstraint::Union> instance.
381 =item B<export_type_contstraints_as_functions>
383 This will export all the current type constraints as functions
384 into the caller's namespace. Right now, this is mostly used for
385 testing, but it might prove useful to others.
387 =item B<list_all_type_constraints>
389 This will return a list of type constraint names, you can then
390 fetch them using C<find_type_constraint ($type_name)> if you
393 =item B<list_all_builtin_type_constraints>
395 This will return a list of builtin type constraints, meaning,
396 those which are defined in this module. See the section
397 labeled L<Default Type Constraints> for a complete list.
401 =head2 Type Constraint Constructors
403 The following functions are used to create type constraints.
404 They will then register the type constraints in a global store
405 where Moose can get to them if it needs to.
407 See the L<SYNOPOSIS> for an example of how to use these.
411 =item B<type ($name, $where_clause)>
413 This creates a base type, which has no parent.
415 =item B<subtype ($name, $parent, $where_clause, ?$message)>
417 This creates a named subtype.
419 =item B<subtype ($parent, $where_clause, ?$message)>
421 This creates an unnamed subtype and will return the type
422 constraint meta-object, which will be an instance of
423 L<Moose::Meta::TypeConstraint>.
425 =item B<enum ($name, @values)>
427 This will create a basic subtype for a given set of strings.
428 The resulting constraint will be a subtype of C<Str> and
429 will match any of the items in C<@values>. See the L<SYNOPSIS>
430 for a simple example.
432 B<NOTE:> This is not a true proper enum type, it is simple
433 a convient constraint builder.
437 This is just sugar for the type constraint construction syntax.
441 This is just sugar for the type constraint construction syntax.
445 This is just sugar for the type constraint construction syntax.
449 This can be used to define a "hand optimized" version of your
450 type constraint which can be used to avoid traversing a subtype
451 constraint heirarchy.
453 B<NOTE:> You should only use this if you know what you are doing,
454 all the built in types use this, so your subtypes (assuming they
455 are shallow) will not likely need to use this.
459 =head2 Type Coercion Constructors
461 Type constraints can also contain type coercions as well. If you
462 ask your accessor too coerce, the Moose will run the type-coercion
463 code first, followed by the type constraint check. This feature
464 should be used carefully as it is very powerful and could easily
465 take off a limb if you are not careful.
467 See the L<SYNOPOSIS> for an example of how to use these.
475 This is just sugar for the type coercion construction syntax.
479 This is just sugar for the type coercion construction syntax.
483 =head2 Namespace Management
489 This will remove all the type constraint keywords from the
490 calling class namespace.
496 All complex software has bugs lurking in it, and this module is no
497 exception. If you find a bug please either email me, or add the bug
502 Stevan Little E<lt>stevan@iinteractive.comE<gt>
504 =head1 COPYRIGHT AND LICENSE
506 Copyright 2006, 2007 by Infinity Interactive, Inc.
508 L<http://www.iinteractive.com>
510 This library is free software; you can redistribute it and/or modify
511 it under the same terms as Perl itself.