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