some basic cleanup
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
CommitLineData
a15dff8d 1
2package Moose::Util::TypeConstraints;
3
4use strict;
5use warnings;
6
e90c03d0 7use Carp 'confess';
86629f93 8use Scalar::Util 'blessed', 'reftype';
571dd39f 9use B 'svref_2object';
10use Sub::Exporter;
a15dff8d 11
8de73ff1 12our $VERSION = '0.17';
d44714be 13our $AUTHORITY = 'cpan:STEVAN';
a15dff8d 14
d9b40005 15## --------------------------------------------------------
e85d2a5d 16# Prototyped subs must be predeclared because we have a
17# circular dependency with Moose::Meta::Attribute et. al.
18# so in case of us being use'd first the predeclaration
d9b40005 19# ensures the prototypes are in scope when consumers are
20# compiled.
21
22# creation and location
0fbd4b0a 23sub find_type_constraint ($);
24sub find_or_create_type_constraint ($;$);
25sub create_type_constraint_union (@);
26sub create_parameterized_type_constraint ($);
d9b40005 27
28# dah sugah!
29sub type ($$;$$);
30sub subtype ($$;$$$);
31sub coerce ($@);
32sub as ($);
33sub from ($);
34sub where (&);
35sub via (&);
36sub message (&);
37sub optimize_as (&);
38sub enum ($;@);
39
e85d2a5d 40## private stuff ...
d9b40005 41sub _create_type_constraint ($$$;$$);
42sub _install_type_coercions ($$);
43
44## --------------------------------------------------------
8c4acc60 45
4e036ee4 46use Moose::Meta::TypeConstraint;
3726f905 47use Moose::Meta::TypeConstraint::Union;
0fbd4b0a 48use Moose::Meta::TypeConstraint::Parameterized;
2ca63f5d 49use Moose::Meta::TypeCoercion;
3726f905 50use Moose::Meta::TypeCoercion::Union;
22aed3c0 51use Moose::Meta::TypeConstraint::Registry;
4e036ee4 52
571dd39f 53my @exports = qw/
8ecb1fa0 54 type subtype as where message optimize_as
e85d2a5d 55 coerce from via
571dd39f 56 enum
57 find_type_constraint
58/;
59
e85d2a5d 60Sub::Exporter::setup_exporter({
571dd39f 61 exports => \@exports,
62 groups => { default => [':all'] }
63});
64
65sub unimport {
e85d2a5d 66 no strict 'refs';
571dd39f 67 my $class = caller();
68 # loop through the exports ...
69 foreach my $name (@exports) {
70 # if we find one ...
71 if (defined &{$class . '::' . $name}) {
72 my $keyword = \&{$class . '::' . $name};
e85d2a5d 73
571dd39f 74 # make sure it is from Moose
75 my $pkg_name = eval { svref_2object($keyword)->GV->STASH->NAME };
76 next if $@;
77 next if $pkg_name ne 'Moose::Util::TypeConstraints';
e85d2a5d 78
571dd39f 79 # and if it is from Moose then undef the slot
80 delete ${$class . '::'}{$name};
81 }
2c0cbef7 82 }
571dd39f 83}
a15dff8d 84
d9b40005 85## --------------------------------------------------------
86## type registry and some useful functions for it
87## --------------------------------------------------------
88
22aed3c0 89my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new;
587ae0d2 90
d9b40005 91sub get_type_constraint_registry { $REGISTRY }
e85d2a5d 92sub list_all_type_constraints { keys %{$REGISTRY->type_constraints} }
d9b40005 93sub export_type_constraints_as_functions {
94 my $pkg = caller();
95 no strict 'refs';
a0f8153d 96 foreach my $constraint (keys %{$REGISTRY->type_constraints}) {
97 *{"${pkg}::${constraint}"} = $REGISTRY->get_type_constraint($constraint)
98 ->_compiled_type_constraint;
99 }
d9b40005 100}
182134e8 101
d9b40005 102sub create_type_constraint_union (@) {
103 my @type_constraint_names;
e85d2a5d 104
f1917f58 105 if (scalar @_ == 1 && _detect_type_constraint_union($_[0])) {
106 @type_constraint_names = _parse_type_constraint_union($_[0]);
d9b40005 107 }
108 else {
109 @type_constraint_names = @_;
429ccc11 110 }
e85d2a5d 111
3726f905 112 (scalar @type_constraint_names >= 2)
e85d2a5d 113 || confess "You must pass in at least 2 type names to make a union";
114
d9b40005 115 ($REGISTRY->has_type_constraint($_))
116 || confess "Could not locate type constraint ($_) for the union"
117 foreach @type_constraint_names;
e85d2a5d 118
3726f905 119 return Moose::Meta::TypeConstraint::Union->new(
120 type_constraints => [
e85d2a5d 121 map {
122 $REGISTRY->get_type_constraint($_)
123 } @type_constraint_names
3726f905 124 ],
e85d2a5d 125 );
182134e8 126}
a15dff8d 127
0fbd4b0a 128sub create_parameterized_type_constraint ($) {
d9b40005 129 my $type_constraint_name = shift;
e85d2a5d 130
0fbd4b0a 131 my ($base_type, $type_parameter) = _parse_parameterized_type_constraint($type_constraint_name);
e85d2a5d 132
0fbd4b0a 133 (defined $base_type && defined $type_parameter)
d9b40005 134 || confess "Could not parse type name ($type_constraint_name) correctly";
e85d2a5d 135
d9b40005 136 ($REGISTRY->has_type_constraint($base_type))
137 || confess "Could not locate the base type ($base_type)";
e85d2a5d 138
0fbd4b0a 139 return Moose::Meta::TypeConstraint::Parameterized->new(
d9b40005 140 name => $type_constraint_name,
141 parent => $REGISTRY->get_type_constraint($base_type),
0fbd4b0a 142 type_parameter => find_or_create_type_constraint(
143 $type_parameter => {
f1917f58 144 parent => $REGISTRY->get_type_constraint('Object'),
0fbd4b0a 145 constraint => sub { $_[0]->isa($type_parameter) }
f1917f58 146 }
147 ),
e85d2a5d 148 );
22aed3c0 149}
150
d9b40005 151sub find_or_create_type_constraint ($;$) {
152 my ($type_constraint_name, $options_for_anon_type) = @_;
e85d2a5d 153
d9b40005 154 return $REGISTRY->get_type_constraint($type_constraint_name)
155 if $REGISTRY->has_type_constraint($type_constraint_name);
e85d2a5d 156
d9b40005 157 my $constraint;
e85d2a5d 158
f1917f58 159 if (_detect_type_constraint_union($type_constraint_name)) {
d9b40005 160 $constraint = create_type_constraint_union($type_constraint_name);
161 }
0fbd4b0a 162 elsif (_detect_parameterized_type_constraint($type_constraint_name)) {
e85d2a5d 163 $constraint = create_parameterized_type_constraint($type_constraint_name);
d9b40005 164 }
165 else {
166 # NOTE:
f3c4e20e 167 # if there is no $options_for_anon_type
168 # specified, then we assume they don't
169 # want to create one, and return nothing.
170 return unless defined $options_for_anon_type;
171
172 # NOTE:
d9b40005 173 # otherwise assume that we should create
e85d2a5d 174 # an ANON type with the $options_for_anon_type
d9b40005 175 # options which can be passed in. It should
e85d2a5d 176 # be noted that these don't get registered
d9b40005 177 # so we need to return it.
178 # - SL
179 return Moose::Meta::TypeConstraint->new(
180 name => '__ANON__',
e85d2a5d 181 %{$options_for_anon_type}
d9b40005 182 );
183 }
e85d2a5d 184
d9b40005 185 $REGISTRY->add_type_constraint($constraint);
e85d2a5d 186 return $constraint;
d9b40005 187}
22aed3c0 188
189## --------------------------------------------------------
190## exported functions ...
191## --------------------------------------------------------
192
193sub find_type_constraint ($) { $REGISTRY->get_type_constraint(@_) }
194
7c13858b 195# type constructors
a15dff8d 196
815ec671 197sub type ($$;$$) {
1b7df21f 198 splice(@_, 1, 0, undef);
a0f8153d 199 goto &_create_type_constraint;
a15dff8d 200}
201
8ecb1fa0 202sub subtype ($$;$$$) {
86629f93 203 # NOTE:
204 # this adds an undef for the name
205 # if this is an anon-subtype:
206 # subtype(Num => where { $_ % 2 == 0 }) # anon 'even' subtype
207 # but if the last arg is not a code
208 # ref then it is a subtype alias:
209 # subtype(MyNumbers => as Num); # now MyNumbers is the same as Num
e85d2a5d 210 # ... yeah I know it's ugly code
86629f93 211 # - SL
a0f8153d 212 unshift @_ => undef if scalar @_ <= 2 && (reftype($_[1]) || '') eq 'CODE';
213 goto &_create_type_constraint;
a15dff8d 214}
215
4b598ea3 216sub coerce ($@) {
e85d2a5d 217 my ($type_name, @coercion_map) = @_;
7c13858b 218 _install_type_coercions($type_name, \@coercion_map);
182134e8 219}
220
76d37e5a 221sub as ($) { $_[0] }
222sub from ($) { $_[0] }
223sub where (&) { $_[0] }
224sub via (&) { $_[0] }
8ecb1fa0 225
226sub message (&) { +{ message => $_[0] } }
227sub optimize_as (&) { +{ optimized => $_[0] } }
a15dff8d 228
2c0cbef7 229sub enum ($;@) {
fcec2383 230 my ($type_name, @values) = @_;
2c0cbef7 231 (scalar @values >= 2)
232 || confess "You must have at least two values to enumerate through";
c4fe165f 233 my %valid = map { $_ => 1 } @values;
a0f8153d 234 _create_type_constraint(
235 $type_name,
236 'Str',
237 sub { $valid{$_} }
238 );
fcec2383 239}
240
d9b40005 241## --------------------------------------------------------
242## desugaring functions ...
243## --------------------------------------------------------
244
e85d2a5d 245sub _create_type_constraint ($$$;$$) {
d9b40005 246 my $name = shift;
247 my $parent = shift;
8de73ff1 248 my $check = shift;
e85d2a5d 249
d9b40005 250 my ($message, $optimized);
251 for (@_) {
252 $message = $_->{message} if exists $_->{message};
e85d2a5d 253 $optimized = $_->{optimized} if exists $_->{optimized};
d9b40005 254 }
255
256 my $pkg_defined_in = scalar(caller(0));
e85d2a5d 257
d9b40005 258 if (defined $name) {
259 my $type = $REGISTRY->get_type_constraint($name);
e85d2a5d 260
d9b40005 261 ($type->_package_defined_in eq $pkg_defined_in)
e85d2a5d 262 || confess ("The type constraint '$name' has already been created in "
d9b40005 263 . $type->_package_defined_in . " and cannot be created again in "
264 . $pkg_defined_in)
e85d2a5d 265 if defined $type;
266 }
267
a0f8153d 268 $parent = find_or_create_type_constraint($parent) if defined $parent;
8de73ff1 269
d9b40005 270 my $constraint = Moose::Meta::TypeConstraint->new(
271 name => $name || '__ANON__',
d9b40005 272 package_defined_in => $pkg_defined_in,
e85d2a5d 273
274 ($parent ? (parent => $parent ) : ()),
275 ($check ? (constraint => $check) : ()),
276 ($message ? (message => $message) : ()),
277 ($optimized ? (optimized => $optimized) : ()),
d9b40005 278 );
8de73ff1 279
280 # NOTE:
281 # if we have a type constraint union, and no
282 # type check, this means we are just aliasing
283 # the union constraint, which means we need to
284 # handle this differently.
285 # - SL
286 if (not(defined($check))
287 && $parent->isa('Moose::Meta::TypeConstraint::Union')
288 && $parent->has_coercion
289 ){
290 $constraint->coercion(Moose::Meta::TypeCoercion::Union->new(
291 type_constraint => $parent
292 ));
293 }
d9b40005 294
295 $REGISTRY->add_type_constraint($constraint)
296 if defined $name;
297
298 return $constraint;
299}
300
e85d2a5d 301sub _install_type_coercions ($$) {
d9b40005 302 my ($type_name, $coercion_map) = @_;
303 my $type = $REGISTRY->get_type_constraint($type_name);
304 (!$type->has_coercion)
e85d2a5d 305 || confess "The type coercion for '$type_name' has already been registered";
d9b40005 306 my $type_coercion = Moose::Meta::TypeCoercion->new(
307 type_coercion_map => $coercion_map,
308 type_constraint => $type
e85d2a5d 309 );
d9b40005 310 $type->coercion($type_coercion);
311}
312
313## --------------------------------------------------------
f1917f58 314## type notation parsing ...
315## --------------------------------------------------------
316
317{
e85d2a5d 318 # All I have to say is mugwump++ cause I know
319 # do not even have enough regexp-fu to be able
320 # to have written this (I can only barely
f1917f58 321 # understand it as it is)
e85d2a5d 322 # - SL
323
f1917f58 324 use re "eval";
325
3796382a 326 my $valid_chars = qr{[\w:]};
f1917f58 327 my $type_atom = qr{ $valid_chars+ };
328
329 my $type = qr{ $valid_chars+ (?: \[ (??{$any}) \] )? }x;
330 my $type_capture_parts = qr{ ($valid_chars+) (?: \[ ((??{$any})) \] )? }x;
331 my $type_with_parameter = qr{ $valid_chars+ \[ (??{$any}) \] }x;
332
3796382a 333 my $op_union = qr{ \s* \| \s* }x;
f1917f58 334 my $union = qr{ $type (?: $op_union $type )+ }x;
335
336 our $any = qr{ $type | $union }x;
337
0fbd4b0a 338 sub _parse_parameterized_type_constraint {
e85d2a5d 339 $_[0] =~ m{ $type_capture_parts }x;
340 return ($1, $2);
f1917f58 341 }
342
0fbd4b0a 343 sub _detect_parameterized_type_constraint {
e85d2a5d 344 $_[0] =~ m{ ^ $type_with_parameter $ }x;
f1917f58 345 }
346
347 sub _parse_type_constraint_union {
e85d2a5d 348 my $given = shift;
349 my @rv;
350 while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) {
351 push @rv => $1;
352 }
353 (pos($given) eq length($given))
354 || confess "'$given' didn't parse (parse-pos="
355 . pos($given)
356 . " and str-length="
357 . length($given)
358 . ")";
359 @rv;
f1917f58 360 }
361
362 sub _detect_type_constraint_union {
e85d2a5d 363 $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x;
f1917f58 364 }
365}
366
367## --------------------------------------------------------
d9b40005 368# define some basic built-in types
369## --------------------------------------------------------
a15dff8d 370
f65cb534 371type 'Any' => where { 1 }; # meta-type including all
e85d2a5d 372type 'Item' => where { 1 }; # base-type
a15dff8d 373
f65cb534 374subtype 'Undef' => as 'Item' => where { !defined($_) };
375subtype 'Defined' => as 'Item' => where { defined($_) };
a15dff8d 376
8ecb1fa0 377subtype 'Bool'
e85d2a5d 378 => as 'Item'
8ecb1fa0 379 => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
5a4c5493 380
e85d2a5d 381subtype 'Value'
382 => as 'Defined'
383 => where { !ref($_) }
8ecb1fa0 384 => optimize_as { defined($_[0]) && !ref($_[0]) };
e85d2a5d 385
8ecb1fa0 386subtype 'Ref'
e85d2a5d 387 => as 'Defined'
388 => where { ref($_) }
8ecb1fa0 389 => optimize_as { ref($_[0]) };
390
e85d2a5d 391subtype 'Str'
392 => as 'Value'
393 => where { 1 }
8ecb1fa0 394 => optimize_as { defined($_[0]) && !ref($_[0]) };
395
e85d2a5d 396subtype 'Num'
397 => as 'Value'
398 => where { Scalar::Util::looks_like_number($_) }
8ecb1fa0 399 => optimize_as { !ref($_[0]) && Scalar::Util::looks_like_number($_[0]) };
e85d2a5d 400
401subtype 'Int'
402 => as 'Num'
8ecb1fa0 403 => where { "$_" =~ /^-?[0-9]+$/ }
404 => optimize_as { defined($_[0]) && !ref($_[0]) && $_[0] =~ /^-?[0-9]+$/ };
405
406subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } => optimize_as { ref($_[0]) eq 'SCALAR' };
407subtype 'ArrayRef' => as 'Ref' => where { ref($_) eq 'ARRAY' } => optimize_as { ref($_[0]) eq 'ARRAY' };
e85d2a5d 408subtype 'HashRef' => as 'Ref' => where { ref($_) eq 'HASH' } => optimize_as { ref($_[0]) eq 'HASH' };
8ecb1fa0 409subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } => optimize_as { ref($_[0]) eq 'CODE' };
e85d2a5d 410subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } => optimize_as { ref($_[0]) eq 'Regexp' };
8ecb1fa0 411subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } => optimize_as { ref($_[0]) eq 'GLOB' };
a15dff8d 412
0a5bd159 413# NOTE:
e85d2a5d 414# scalar filehandles are GLOB refs,
0a5bd159 415# but a GLOB ref is not always a filehandle
e85d2a5d 416subtype 'FileHandle'
417 => as 'GlobRef'
8ecb1fa0 418 => where { Scalar::Util::openhandle($_) }
419 => optimize_as { ref($_[0]) eq 'GLOB' && Scalar::Util::openhandle($_[0]) };
0a5bd159 420
e85d2a5d 421# NOTE:
a15dff8d 422# blessed(qr/.../) returns true,.. how odd
e85d2a5d 423subtype 'Object'
424 => as 'Ref'
8ecb1fa0 425 => where { blessed($_) && blessed($_) ne 'Regexp' }
426 => optimize_as { blessed($_[0]) && blessed($_[0]) ne 'Regexp' };
a15dff8d 427
e85d2a5d 428subtype 'Role'
429 => as 'Object'
8ecb1fa0 430 => where { $_->can('does') }
431 => optimize_as { blessed($_[0]) && $_[0]->can('does') };
e85d2a5d 432
0e0709ea 433my $_class_name_checker = sub {
434 return if ref($_[0]);
435 return unless defined($_[0]) && length($_[0]);
436
437 # walk the symbol table tree to avoid autovififying
438 # \*{${main::}{"Foo::"}} == \*main::Foo::
439
440 my $pack = \*::;
441 foreach my $part (split('::', $_[0])) {
442 return unless exists ${$$pack}{"${part}::"};
443 $pack = \*{${$$pack}{"${part}::"}};
444 }
445
446 # check for $VERSION or @ISA
447 return 1 if exists ${$$pack}{VERSION}
448 && defined *{${$$pack}{VERSION}}{SCALAR};
449 return 1 if exists ${$$pack}{ISA}
450 && defined *{${$$pack}{ISA}}{ARRAY};
451
452 # check for any method
453 foreach ( keys %{$$pack} ) {
454 next if substr($_, -2, 2) eq '::';
455 return 1 if defined *{${$$pack}{$_}}{CODE};
456 }
457
458 # fail
459 return;
460};
461
e85d2a5d 462subtype 'ClassName'
463 => as 'Str'
0e0709ea 464 => $_class_name_checker # where ...
465 => { optimize => $_class_name_checker };
02a0fb52 466
d9b40005 467## --------------------------------------------------------
468# end of built-in types ...
469## --------------------------------------------------------
470
943596a6 471{
472 my @BUILTINS = list_all_type_constraints();
473 sub list_all_builtin_type_constraints { @BUILTINS }
474}
475
a15dff8d 4761;
477
478__END__
479
480=pod
481
482=head1 NAME
483
e522431d 484Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 485
486=head1 SYNOPSIS
487
488 use Moose::Util::TypeConstraints;
489
2c0cbef7 490 type 'Num' => where { Scalar::Util::looks_like_number($_) };
e85d2a5d 491
492 subtype 'Natural'
493 => as 'Num'
a15dff8d 494 => where { $_ > 0 };
e85d2a5d 495
496 subtype 'NaturalLessThanTen'
2c0cbef7 497 => as 'Natural'
79592a54 498 => where { $_ < 10 }
499 => message { "This number ($_) is not less than ten!" };
e85d2a5d 500
501 coerce 'Num'
2c0cbef7 502 => from 'Str'
e85d2a5d 503 => via { 0+$_ };
504
2c0cbef7 505 enum 'RGBColors' => qw(red green blue);
a15dff8d 506
507=head1 DESCRIPTION
508
e85d2a5d 509This module provides Moose with the ability to create custom type
510contraints to be used in attribute definition.
e522431d 511
6ba6d68c 512=head2 Important Caveat
513
e85d2a5d 514This is B<NOT> a type system for Perl 5. These are type constraints,
515and they are not used by Moose unless you tell it to. No type
516inference is performed, expression are not typed, etc. etc. etc.
6ba6d68c 517
e85d2a5d 518This is simply a means of creating small constraint functions which
a7d0cd00 519can be used to simplify your own type-checking code.
6ba6d68c 520
2c0cbef7 521=head2 Slightly Less Important Caveat
522
e85d2a5d 523It is almost always a good idea to quote your type and subtype names.
524This is to prevent perl from trying to execute the call as an indirect
2c0cbef7 525object call. This issue only seems to come up when you have a subtype
e85d2a5d 526the same name as a valid class, but when the issue does arise it tends
527to be quite annoying to debug.
2c0cbef7 528
529So for instance, this:
e85d2a5d 530
2c0cbef7 531 subtype DateTime => as Object => where { $_->isa('DateTime') };
532
533will I<Just Work>, while this:
534
535 use DateTime;
536 subtype DateTime => as Object => where { $_->isa('DateTime') };
537
e85d2a5d 538will fail silently and cause many headaches. The simple way to solve
539this, as well as future proof your subtypes from classes which have
2c0cbef7 540yet to have been created yet, is to simply do this:
541
542 use DateTime;
d44714be 543 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 544
6ba6d68c 545=head2 Default Type Constraints
e522431d 546
e85d2a5d 547This module also provides a simple hierarchy for Perl 5 types, this
e522431d 548could probably use some work, but it works for me at the moment.
549
550 Any
e85d2a5d 551 Item
5a4c5493 552 Bool
f65cb534 553 Undef
554 Defined
5a4c5493 555 Value
556 Num
557 Int
558 Str
9af1d28b 559 ClassName
5a4c5493 560 Ref
561 ScalarRef
451c8248 562 ArrayRef
563 HashRef
5a4c5493 564 CodeRef
565 RegexpRef
3f7376b0 566 GlobRef
0a5bd159 567 FileHandle
e85d2a5d 568 Object
5a4c5493 569 Role
e522431d 570
6ba6d68c 571Suggestions for improvement are welcome.
2c0cbef7 572
e85d2a5d 573B<NOTE:> The C<Undef> type constraint does not work correctly
2c0cbef7 574in every occasion, please use it sparringly.
703e92fb 575
e85d2a5d 576B<NOTE:> The C<ClassName> type constraint is simply a subtype
9af1d28b 577of string which responds true to C<isa('UNIVERSAL')>. This means
e85d2a5d 578that your class B<must> be loaded for this type constraint to
579pass. I know this is not ideal for all, but it is a saner
580restriction than most others.
9af1d28b 581
703e92fb 582=head2 Use with Other Constraint Modules
583
e85d2a5d 584This module should play fairly nicely with other constraint
585modules with only some slight tweaking. The C<where> clause
703e92fb 586in types is expected to be a C<CODE> reference which checks
587it's first argument and returns a bool. Since most constraint
e85d2a5d 588modules work in a similar way, it should be simple to adapt
703e92fb 589them to work with Moose.
590
e85d2a5d 591For instance, this is how you could use it with
592L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 593
e85d2a5d 594 type 'HashOfArrayOfObjects'
703e92fb 595 => IsHashRef(
596 -keys => HasLength,
597 -values => IsArrayRef( IsObject ));
598
599For more examples see the F<t/204_example_w_DCS.t> test file.
600
e85d2a5d 601Here is an example of using L<Test::Deep> and it's non-test
602related C<eq_deeply> function.
703e92fb 603
e85d2a5d 604 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 605 => where {
e85d2a5d 606 eq_deeply($_,
703e92fb 607 array_each(subhashof({
608 bar => isa('Bar'),
609 random_number => ignore()
e85d2a5d 610 })))
703e92fb 611 };
612
e85d2a5d 613For a complete example see the F<t/205_example_w_TestDeep.t>
614test file.
615
a15dff8d 616=head1 FUNCTIONS
617
d9b40005 618=head2 Type Constraint Construction & Locating
182134e8 619
620=over 4
621
d9b40005 622=item B<create_type_constraint_union ($pipe_seperated_types | @type_constraint_names)>
182134e8 623
e85d2a5d 624Given string with C<$pipe_seperated_types> or a list of C<@type_constraint_names>,
d9b40005 625this will return a L<Moose::Meta::TypeConstraint::Union> instance.
182134e8 626
0fbd4b0a 627=item B<create_parameterized_type_constraint ($type_name)>
c07af9d2 628
d9b40005 629Given a C<$type_name> in the form of:
c07af9d2 630
d9b40005 631 BaseType[ContainerType]
182134e8 632
e85d2a5d 633this will extract the base type and container type and build an instance of
0fbd4b0a 634L<Moose::Meta::TypeConstraint::Parameterized> for it.
d9b40005 635
636=item B<find_or_create_type_constraint ($type_name, ?$options_for_anon_type)>
6ba6d68c 637
e85d2a5d 638This will attempt to find or create a type constraint given the a C<$type_name>.
639If it cannot find it in the registry, it will see if it should be a union or
640container type an create one if appropriate, and lastly if nothing can be
641found or created that way, it will create an anon-type using the
f3c4e20e 642C<$options_for_anon_type> HASH ref to populate it. If the C<$options_for_anon_type>
643is not specified (it is C<undef>), then it will not create anything and simply
644return.
429ccc11 645
d9b40005 646=item B<find_type_constraint ($type_name)>
647
648This function can be used to locate a specific type constraint
649meta-object, of the class L<Moose::Meta::TypeConstraint> or a
650derivative. What you do with it from there is up to you :)
651
652=item B<get_type_constraint_registry>
653
e85d2a5d 654Fetch the L<Moose::Meta::TypeConstraint::Registry> object which
d9b40005 655keeps track of all type constraints.
429ccc11 656
b1e01e3c 657=item B<list_all_type_constraints>
658
e85d2a5d 659This will return a list of type constraint names, you can then
660fetch them using C<find_type_constraint ($type_name)> if you
b1e01e3c 661want to.
662
943596a6 663=item B<list_all_builtin_type_constraints>
664
e85d2a5d 665This will return a list of builtin type constraints, meaning,
666those which are defined in this module. See the section
943596a6 667labeled L<Default Type Constraints> for a complete list.
668
d9b40005 669=item B<export_type_constraints_as_functions>
670
e85d2a5d 671This will export all the current type constraints as functions
672into the caller's namespace. Right now, this is mostly used for
d9b40005 673testing, but it might prove useful to others.
674
182134e8 675=back
676
a15dff8d 677=head2 Type Constraint Constructors
678
e85d2a5d 679The following functions are used to create type constraints.
680They will then register the type constraints in a global store
681where Moose can get to them if it needs to.
a15dff8d 682
25f2c3fc 683See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 684
6ba6d68c 685=over 4
a15dff8d 686
6ba6d68c 687=item B<type ($name, $where_clause)>
a15dff8d 688
e85d2a5d 689This creates a base type, which has no parent.
a15dff8d 690
79592a54 691=item B<subtype ($name, $parent, $where_clause, ?$message)>
182134e8 692
e85d2a5d 693This creates a named subtype.
d6e2d9a1 694
79592a54 695=item B<subtype ($parent, $where_clause, ?$message)>
182134e8 696
e85d2a5d 697This creates an unnamed subtype and will return the type
698constraint meta-object, which will be an instance of
699L<Moose::Meta::TypeConstraint>.
a15dff8d 700
fcec2383 701=item B<enum ($name, @values)>
702
e85d2a5d 703This will create a basic subtype for a given set of strings.
704The resulting constraint will be a subtype of C<Str> and
4ce56d04 705will match any of the items in C<@values>. It is case sensitive.
706See the L<SYNOPSIS> for a simple example.
2c0cbef7 707
e85d2a5d 708B<NOTE:> This is not a true proper enum type, it is simple
2c0cbef7 709a convient constraint builder.
710
6ba6d68c 711=item B<as>
a15dff8d 712
6ba6d68c 713This is just sugar for the type constraint construction syntax.
a15dff8d 714
6ba6d68c 715=item B<where>
a15dff8d 716
6ba6d68c 717This is just sugar for the type constraint construction syntax.
76d37e5a 718
719=item B<message>
720
721This is just sugar for the type constraint construction syntax.
a15dff8d 722
8ecb1fa0 723=item B<optimize_as>
724
e85d2a5d 725This can be used to define a "hand optimized" version of your
d44714be 726type constraint which can be used to avoid traversing a subtype
e85d2a5d 727constraint heirarchy.
d44714be 728
e85d2a5d 729B<NOTE:> You should only use this if you know what you are doing,
730all the built in types use this, so your subtypes (assuming they
d44714be 731are shallow) will not likely need to use this.
732
6ba6d68c 733=back
a15dff8d 734
6ba6d68c 735=head2 Type Coercion Constructors
a15dff8d 736
e85d2a5d 737Type constraints can also contain type coercions as well. If you
738ask your accessor to coerce, then Moose will run the type-coercion
739code first, followed by the type constraint check. This feature
740should be used carefully as it is very powerful and could easily
587ae0d2 741take off a limb if you are not careful.
a15dff8d 742
25f2c3fc 743See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 744
6ba6d68c 745=over 4
a15dff8d 746
6ba6d68c 747=item B<coerce>
a15dff8d 748
6ba6d68c 749=item B<from>
a15dff8d 750
6ba6d68c 751This is just sugar for the type coercion construction syntax.
752
753=item B<via>
a15dff8d 754
6ba6d68c 755This is just sugar for the type coercion construction syntax.
a15dff8d 756
757=back
758
571dd39f 759=head2 Namespace Management
760
761=over 4
762
763=item B<unimport>
764
e85d2a5d 765This will remove all the type constraint keywords from the
571dd39f 766calling class namespace.
767
768=back
769
a15dff8d 770=head1 BUGS
771
e85d2a5d 772All complex software has bugs lurking in it, and this module is no
a15dff8d 773exception. If you find a bug please either email me, or add the bug
774to cpan-RT.
775
a15dff8d 776=head1 AUTHOR
777
778Stevan Little E<lt>stevan@iinteractive.comE<gt>
779
780=head1 COPYRIGHT AND LICENSE
781
b77fdbed 782Copyright 2006, 2007 by Infinity Interactive, Inc.
a15dff8d 783
784L<http://www.iinteractive.com>
785
786This library is free software; you can redistribute it and/or modify
e85d2a5d 787it under the same terms as Perl itself.
a15dff8d 788
81dc201f 789=cut