HATE SVK!!! missing file for the typeconstraint refac
[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;
28ffb449 51use Moose::Util::TypeConstraints::OptimizedConstraints;
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
53dd42d8 75 my ($pkg_name) = Class::MOP::get_code_info($keyword);
571dd39f 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
6f9ff1af 286 if (not(defined $check)
8de73ff1 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);
6f9ff1af 304 (defined $type)
305 || confess "Cannot find type '$type_name', perhaps you forgot to load it.";
41e007e4 306 if ($type->has_coercion) {
307 $type->coercion->add_type_coercions(@$coercion_map);
308 }
309 else {
310 my $type_coercion = Moose::Meta::TypeCoercion->new(
311 type_coercion_map => $coercion_map,
312 type_constraint => $type
313 );
314 $type->coercion($type_coercion);
315 }
d9b40005 316}
317
318## --------------------------------------------------------
f1917f58 319## type notation parsing ...
320## --------------------------------------------------------
321
322{
e85d2a5d 323 # All I have to say is mugwump++ cause I know
324 # do not even have enough regexp-fu to be able
325 # to have written this (I can only barely
f1917f58 326 # understand it as it is)
e85d2a5d 327 # - SL
328
f1917f58 329 use re "eval";
330
3796382a 331 my $valid_chars = qr{[\w:]};
f1917f58 332 my $type_atom = qr{ $valid_chars+ };
333
334 my $type = qr{ $valid_chars+ (?: \[ (??{$any}) \] )? }x;
335 my $type_capture_parts = qr{ ($valid_chars+) (?: \[ ((??{$any})) \] )? }x;
336 my $type_with_parameter = qr{ $valid_chars+ \[ (??{$any}) \] }x;
337
3796382a 338 my $op_union = qr{ \s* \| \s* }x;
f1917f58 339 my $union = qr{ $type (?: $op_union $type )+ }x;
340
341 our $any = qr{ $type | $union }x;
342
0fbd4b0a 343 sub _parse_parameterized_type_constraint {
e85d2a5d 344 $_[0] =~ m{ $type_capture_parts }x;
345 return ($1, $2);
f1917f58 346 }
347
0fbd4b0a 348 sub _detect_parameterized_type_constraint {
e85d2a5d 349 $_[0] =~ m{ ^ $type_with_parameter $ }x;
f1917f58 350 }
351
352 sub _parse_type_constraint_union {
e85d2a5d 353 my $given = shift;
354 my @rv;
355 while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) {
356 push @rv => $1;
357 }
358 (pos($given) eq length($given))
359 || confess "'$given' didn't parse (parse-pos="
360 . pos($given)
361 . " and str-length="
362 . length($given)
363 . ")";
364 @rv;
f1917f58 365 }
366
367 sub _detect_type_constraint_union {
e85d2a5d 368 $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x;
f1917f58 369 }
370}
371
372## --------------------------------------------------------
d9b40005 373# define some basic built-in types
374## --------------------------------------------------------
a15dff8d 375
f65cb534 376type 'Any' => where { 1 }; # meta-type including all
e85d2a5d 377type 'Item' => where { 1 }; # base-type
a15dff8d 378
f65cb534 379subtype 'Undef' => as 'Item' => where { !defined($_) };
380subtype 'Defined' => as 'Item' => where { defined($_) };
a15dff8d 381
8ecb1fa0 382subtype 'Bool'
e85d2a5d 383 => as 'Item'
8ecb1fa0 384 => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
5a4c5493 385
e85d2a5d 386subtype 'Value'
387 => as 'Defined'
388 => where { !ref($_) }
28ffb449 389 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Value;
e85d2a5d 390
8ecb1fa0 391subtype 'Ref'
e85d2a5d 392 => as 'Defined'
393 => where { ref($_) }
28ffb449 394 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Ref;
8ecb1fa0 395
e85d2a5d 396subtype 'Str'
397 => as 'Value'
398 => where { 1 }
28ffb449 399 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Str;
8ecb1fa0 400
e85d2a5d 401subtype 'Num'
402 => as 'Value'
403 => where { Scalar::Util::looks_like_number($_) }
28ffb449 404 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Num;
e85d2a5d 405
406subtype 'Int'
407 => as 'Num'
8ecb1fa0 408 => where { "$_" =~ /^-?[0-9]+$/ }
28ffb449 409 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Int;
8ecb1fa0 410
28ffb449 411subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef;
412subtype 'ArrayRef' => as 'Ref' => where { ref($_) eq 'ARRAY' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::ArrayRef;
413subtype 'HashRef' => as 'Ref' => where { ref($_) eq 'HASH' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::HashRef;
414subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::CodeRef;
415subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::RegexpRef;
416subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::GlobRef;
a15dff8d 417
0a5bd159 418# NOTE:
e85d2a5d 419# scalar filehandles are GLOB refs,
0a5bd159 420# but a GLOB ref is not always a filehandle
e85d2a5d 421subtype 'FileHandle'
422 => as 'GlobRef'
8ecb1fa0 423 => where { Scalar::Util::openhandle($_) }
28ffb449 424 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::FileHandle;
0a5bd159 425
e85d2a5d 426# NOTE:
a15dff8d 427# blessed(qr/.../) returns true,.. how odd
e85d2a5d 428subtype 'Object'
429 => as 'Ref'
8ecb1fa0 430 => where { blessed($_) && blessed($_) ne 'Regexp' }
28ffb449 431 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Object;
a15dff8d 432
e85d2a5d 433subtype 'Role'
434 => as 'Object'
8ecb1fa0 435 => where { $_->can('does') }
28ffb449 436 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Role;
e85d2a5d 437
0e0709ea 438my $_class_name_checker = sub {
439 return if ref($_[0]);
440 return unless defined($_[0]) && length($_[0]);
441
442 # walk the symbol table tree to avoid autovififying
443 # \*{${main::}{"Foo::"}} == \*main::Foo::
444
445 my $pack = \*::;
446 foreach my $part (split('::', $_[0])) {
447 return unless exists ${$$pack}{"${part}::"};
448 $pack = \*{${$$pack}{"${part}::"}};
449 }
450
451 # check for $VERSION or @ISA
452 return 1 if exists ${$$pack}{VERSION}
453 && defined *{${$$pack}{VERSION}}{SCALAR};
454 return 1 if exists ${$$pack}{ISA}
455 && defined *{${$$pack}{ISA}}{ARRAY};
456
457 # check for any method
458 foreach ( keys %{$$pack} ) {
459 next if substr($_, -2, 2) eq '::';
460 return 1 if defined *{${$$pack}{$_}}{CODE};
461 }
462
463 # fail
464 return;
465};
466
e85d2a5d 467subtype 'ClassName'
468 => as 'Str'
0e0709ea 469 => $_class_name_checker # where ...
470 => { optimize => $_class_name_checker };
02a0fb52 471
d9b40005 472## --------------------------------------------------------
473# end of built-in types ...
474## --------------------------------------------------------
475
943596a6 476{
477 my @BUILTINS = list_all_type_constraints();
478 sub list_all_builtin_type_constraints { @BUILTINS }
479}
480
a15dff8d 4811;
482
483__END__
484
485=pod
486
487=head1 NAME
488
e522431d 489Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 490
491=head1 SYNOPSIS
492
493 use Moose::Util::TypeConstraints;
494
2c0cbef7 495 type 'Num' => where { Scalar::Util::looks_like_number($_) };
e85d2a5d 496
497 subtype 'Natural'
498 => as 'Num'
a15dff8d 499 => where { $_ > 0 };
e85d2a5d 500
501 subtype 'NaturalLessThanTen'
2c0cbef7 502 => as 'Natural'
79592a54 503 => where { $_ < 10 }
504 => message { "This number ($_) is not less than ten!" };
e85d2a5d 505
506 coerce 'Num'
2c0cbef7 507 => from 'Str'
e85d2a5d 508 => via { 0+$_ };
509
2c0cbef7 510 enum 'RGBColors' => qw(red green blue);
a15dff8d 511
512=head1 DESCRIPTION
513
e85d2a5d 514This module provides Moose with the ability to create custom type
515contraints to be used in attribute definition.
e522431d 516
6ba6d68c 517=head2 Important Caveat
518
e85d2a5d 519This is B<NOT> a type system for Perl 5. These are type constraints,
520and they are not used by Moose unless you tell it to. No type
521inference is performed, expression are not typed, etc. etc. etc.
6ba6d68c 522
e85d2a5d 523This is simply a means of creating small constraint functions which
a7d0cd00 524can be used to simplify your own type-checking code.
6ba6d68c 525
2c0cbef7 526=head2 Slightly Less Important Caveat
527
e85d2a5d 528It is almost always a good idea to quote your type and subtype names.
529This is to prevent perl from trying to execute the call as an indirect
2c0cbef7 530object call. This issue only seems to come up when you have a subtype
e85d2a5d 531the same name as a valid class, but when the issue does arise it tends
532to be quite annoying to debug.
2c0cbef7 533
534So for instance, this:
e85d2a5d 535
2c0cbef7 536 subtype DateTime => as Object => where { $_->isa('DateTime') };
537
538will I<Just Work>, while this:
539
540 use DateTime;
541 subtype DateTime => as Object => where { $_->isa('DateTime') };
542
e85d2a5d 543will fail silently and cause many headaches. The simple way to solve
544this, as well as future proof your subtypes from classes which have
2c0cbef7 545yet to have been created yet, is to simply do this:
546
547 use DateTime;
d44714be 548 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 549
6ba6d68c 550=head2 Default Type Constraints
e522431d 551
e85d2a5d 552This module also provides a simple hierarchy for Perl 5 types, this
e522431d 553could probably use some work, but it works for me at the moment.
554
555 Any
e85d2a5d 556 Item
5a4c5493 557 Bool
f65cb534 558 Undef
559 Defined
5a4c5493 560 Value
561 Num
562 Int
563 Str
9af1d28b 564 ClassName
5a4c5493 565 Ref
566 ScalarRef
451c8248 567 ArrayRef
568 HashRef
5a4c5493 569 CodeRef
570 RegexpRef
3f7376b0 571 GlobRef
0a5bd159 572 FileHandle
e85d2a5d 573 Object
5a4c5493 574 Role
e522431d 575
6ba6d68c 576Suggestions for improvement are welcome.
2c0cbef7 577
e85d2a5d 578B<NOTE:> The C<Undef> type constraint does not work correctly
2c0cbef7 579in every occasion, please use it sparringly.
703e92fb 580
e85d2a5d 581B<NOTE:> The C<ClassName> type constraint is simply a subtype
9af1d28b 582of string which responds true to C<isa('UNIVERSAL')>. This means
e85d2a5d 583that your class B<must> be loaded for this type constraint to
584pass. I know this is not ideal for all, but it is a saner
585restriction than most others.
9af1d28b 586
703e92fb 587=head2 Use with Other Constraint Modules
588
e85d2a5d 589This module should play fairly nicely with other constraint
590modules with only some slight tweaking. The C<where> clause
703e92fb 591in types is expected to be a C<CODE> reference which checks
592it's first argument and returns a bool. Since most constraint
e85d2a5d 593modules work in a similar way, it should be simple to adapt
703e92fb 594them to work with Moose.
595
e85d2a5d 596For instance, this is how you could use it with
597L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 598
e85d2a5d 599 type 'HashOfArrayOfObjects'
703e92fb 600 => IsHashRef(
601 -keys => HasLength,
602 -values => IsArrayRef( IsObject ));
603
604For more examples see the F<t/204_example_w_DCS.t> test file.
605
e85d2a5d 606Here is an example of using L<Test::Deep> and it's non-test
607related C<eq_deeply> function.
703e92fb 608
e85d2a5d 609 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 610 => where {
e85d2a5d 611 eq_deeply($_,
703e92fb 612 array_each(subhashof({
613 bar => isa('Bar'),
614 random_number => ignore()
e85d2a5d 615 })))
703e92fb 616 };
617
e85d2a5d 618For a complete example see the F<t/205_example_w_TestDeep.t>
619test file.
620
a15dff8d 621=head1 FUNCTIONS
622
d9b40005 623=head2 Type Constraint Construction & Locating
182134e8 624
625=over 4
626
d9b40005 627=item B<create_type_constraint_union ($pipe_seperated_types | @type_constraint_names)>
182134e8 628
e85d2a5d 629Given string with C<$pipe_seperated_types> or a list of C<@type_constraint_names>,
d9b40005 630this will return a L<Moose::Meta::TypeConstraint::Union> instance.
182134e8 631
0fbd4b0a 632=item B<create_parameterized_type_constraint ($type_name)>
c07af9d2 633
d9b40005 634Given a C<$type_name> in the form of:
c07af9d2 635
d9b40005 636 BaseType[ContainerType]
182134e8 637
e85d2a5d 638this will extract the base type and container type and build an instance of
0fbd4b0a 639L<Moose::Meta::TypeConstraint::Parameterized> for it.
d9b40005 640
641=item B<find_or_create_type_constraint ($type_name, ?$options_for_anon_type)>
6ba6d68c 642
e85d2a5d 643This will attempt to find or create a type constraint given the a C<$type_name>.
644If it cannot find it in the registry, it will see if it should be a union or
645container type an create one if appropriate, and lastly if nothing can be
646found or created that way, it will create an anon-type using the
f3c4e20e 647C<$options_for_anon_type> HASH ref to populate it. If the C<$options_for_anon_type>
648is not specified (it is C<undef>), then it will not create anything and simply
649return.
429ccc11 650
d9b40005 651=item B<find_type_constraint ($type_name)>
652
653This function can be used to locate a specific type constraint
654meta-object, of the class L<Moose::Meta::TypeConstraint> or a
655derivative. What you do with it from there is up to you :)
656
657=item B<get_type_constraint_registry>
658
e85d2a5d 659Fetch the L<Moose::Meta::TypeConstraint::Registry> object which
d9b40005 660keeps track of all type constraints.
429ccc11 661
b1e01e3c 662=item B<list_all_type_constraints>
663
e85d2a5d 664This will return a list of type constraint names, you can then
665fetch them using C<find_type_constraint ($type_name)> if you
b1e01e3c 666want to.
667
943596a6 668=item B<list_all_builtin_type_constraints>
669
e85d2a5d 670This will return a list of builtin type constraints, meaning,
671those which are defined in this module. See the section
943596a6 672labeled L<Default Type Constraints> for a complete list.
673
d9b40005 674=item B<export_type_constraints_as_functions>
675
e85d2a5d 676This will export all the current type constraints as functions
677into the caller's namespace. Right now, this is mostly used for
d9b40005 678testing, but it might prove useful to others.
679
182134e8 680=back
681
a15dff8d 682=head2 Type Constraint Constructors
683
e85d2a5d 684The following functions are used to create type constraints.
685They will then register the type constraints in a global store
686where Moose can get to them if it needs to.
a15dff8d 687
25f2c3fc 688See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 689
6ba6d68c 690=over 4
a15dff8d 691
6ba6d68c 692=item B<type ($name, $where_clause)>
a15dff8d 693
e85d2a5d 694This creates a base type, which has no parent.
a15dff8d 695
79592a54 696=item B<subtype ($name, $parent, $where_clause, ?$message)>
182134e8 697
e85d2a5d 698This creates a named subtype.
d6e2d9a1 699
79592a54 700=item B<subtype ($parent, $where_clause, ?$message)>
182134e8 701
e85d2a5d 702This creates an unnamed subtype and will return the type
703constraint meta-object, which will be an instance of
704L<Moose::Meta::TypeConstraint>.
a15dff8d 705
fcec2383 706=item B<enum ($name, @values)>
707
e85d2a5d 708This will create a basic subtype for a given set of strings.
709The resulting constraint will be a subtype of C<Str> and
4ce56d04 710will match any of the items in C<@values>. It is case sensitive.
711See the L<SYNOPSIS> for a simple example.
2c0cbef7 712
e85d2a5d 713B<NOTE:> This is not a true proper enum type, it is simple
2c0cbef7 714a convient constraint builder.
715
6ba6d68c 716=item B<as>
a15dff8d 717
6ba6d68c 718This is just sugar for the type constraint construction syntax.
a15dff8d 719
6ba6d68c 720=item B<where>
a15dff8d 721
6ba6d68c 722This is just sugar for the type constraint construction syntax.
76d37e5a 723
724=item B<message>
725
726This is just sugar for the type constraint construction syntax.
a15dff8d 727
8ecb1fa0 728=item B<optimize_as>
729
e85d2a5d 730This can be used to define a "hand optimized" version of your
d44714be 731type constraint which can be used to avoid traversing a subtype
e85d2a5d 732constraint heirarchy.
d44714be 733
e85d2a5d 734B<NOTE:> You should only use this if you know what you are doing,
735all the built in types use this, so your subtypes (assuming they
d44714be 736are shallow) will not likely need to use this.
737
6ba6d68c 738=back
a15dff8d 739
6ba6d68c 740=head2 Type Coercion Constructors
a15dff8d 741
e85d2a5d 742Type constraints can also contain type coercions as well. If you
743ask your accessor to coerce, then Moose will run the type-coercion
744code first, followed by the type constraint check. This feature
745should be used carefully as it is very powerful and could easily
587ae0d2 746take off a limb if you are not careful.
a15dff8d 747
25f2c3fc 748See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 749
6ba6d68c 750=over 4
a15dff8d 751
6ba6d68c 752=item B<coerce>
a15dff8d 753
6ba6d68c 754=item B<from>
a15dff8d 755
6ba6d68c 756This is just sugar for the type coercion construction syntax.
757
758=item B<via>
a15dff8d 759
6ba6d68c 760This is just sugar for the type coercion construction syntax.
a15dff8d 761
762=back
763
571dd39f 764=head2 Namespace Management
765
766=over 4
767
768=item B<unimport>
769
e85d2a5d 770This will remove all the type constraint keywords from the
571dd39f 771calling class namespace.
772
773=back
774
a15dff8d 775=head1 BUGS
776
e85d2a5d 777All complex software has bugs lurking in it, and this module is no
a15dff8d 778exception. If you find a bug please either email me, or add the bug
779to cpan-RT.
780
a15dff8d 781=head1 AUTHOR
782
783Stevan Little E<lt>stevan@iinteractive.comE<gt>
784
785=head1 COPYRIGHT AND LICENSE
786
778db3ac 787Copyright 2006-2008 by Infinity Interactive, Inc.
a15dff8d 788
789L<http://www.iinteractive.com>
790
791This library is free software; you can redistribute it and/or modify
e85d2a5d 792it under the same terms as Perl itself.
a15dff8d 793
81dc201f 794=cut