Check that the value is an object in duck_type TC
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
CommitLineData
a15dff8d 1
2package Moose::Util::TypeConstraints;
3
998a8a25 4use Carp ();
9e856c83 5use List::MoreUtils qw( all any );
9a63faba 6use Scalar::Util qw( blessed reftype );
e606ae5f 7use Moose::Exporter;
a15dff8d 8
eae0508f 9our $VERSION = '0.81';
e606ae5f 10$VERSION = eval $VERSION;
d44714be 11our $AUTHORITY = 'cpan:STEVAN';
a15dff8d 12
d9b40005 13## --------------------------------------------------------
e85d2a5d 14# Prototyped subs must be predeclared because we have a
15# circular dependency with Moose::Meta::Attribute et. al.
16# so in case of us being use'd first the predeclaration
d9b40005 17# ensures the prototypes are in scope when consumers are
18# compiled.
19
d9b40005 20# dah sugah!
180899ed 21sub where (&);
22sub via (&);
23sub message (&);
d9b40005 24sub optimize_as (&);
d9b40005 25
d9b40005 26## --------------------------------------------------------
8c4acc60 27
4e036ee4 28use Moose::Meta::TypeConstraint;
3726f905 29use Moose::Meta::TypeConstraint::Union;
0fbd4b0a 30use Moose::Meta::TypeConstraint::Parameterized;
7e4e1ad4 31use Moose::Meta::TypeConstraint::Parameterizable;
620db045 32use Moose::Meta::TypeConstraint::Class;
33use Moose::Meta::TypeConstraint::Role;
dabed765 34use Moose::Meta::TypeConstraint::Enum;
2ca63f5d 35use Moose::Meta::TypeCoercion;
3726f905 36use Moose::Meta::TypeCoercion::Union;
22aed3c0 37use Moose::Meta::TypeConstraint::Registry;
28ffb449 38use Moose::Util::TypeConstraints::OptimizedConstraints;
4e036ee4 39
e606ae5f 40Moose::Exporter->setup_import_methods(
41 as_is => [
42 qw(
180899ed 43 type subtype class_type role_type maybe_type duck_type
1b2c9bda 44 as where message optimize_as
e606ae5f 45 coerce from via
46 enum
47 find_type_constraint
48 register_type_constraint )
49 ],
50 _export_to_main => 1,
51);
a15dff8d 52
d9b40005 53## --------------------------------------------------------
54## type registry and some useful functions for it
55## --------------------------------------------------------
56
22aed3c0 57my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new;
587ae0d2 58
180899ed 59sub get_type_constraint_registry {$REGISTRY}
60sub list_all_type_constraints { keys %{ $REGISTRY->type_constraints } }
61
d9b40005 62sub export_type_constraints_as_functions {
63 my $pkg = caller();
64 no strict 'refs';
180899ed 65 foreach my $constraint ( keys %{ $REGISTRY->type_constraints } ) {
66 my $tc = $REGISTRY->get_type_constraint($constraint)
67 ->_compiled_type_constraint;
68 *{"${pkg}::${constraint}"}
69 = sub { $tc->( $_[0] ) ? 1 : undef }; # the undef is for compat
a0f8153d 70 }
d9b40005 71}
182134e8 72
0c015f1b 73sub create_type_constraint_union {
d9b40005 74 my @type_constraint_names;
e85d2a5d 75
180899ed 76 if ( scalar @_ == 1 && _detect_type_constraint_union( $_[0] ) ) {
77 @type_constraint_names = _parse_type_constraint_union( $_[0] );
d9b40005 78 }
79 else {
80 @type_constraint_names = @_;
429ccc11 81 }
180899ed 82
83 ( scalar @type_constraint_names >= 2 )
84 || __PACKAGE__->_throw_error(
85 "You must pass in at least 2 type names to make a union");
e85d2a5d 86
84a9c64c 87 my @type_constraints = map {
180899ed 88 find_or_parse_type_constraint($_)
89 || __PACKAGE__->_throw_error(
90 "Could not locate type constraint ($_) for the union");
08380fdb 91 } @type_constraint_names;
84a9c64c 92
3726f905 93 return Moose::Meta::TypeConstraint::Union->new(
180899ed 94 type_constraints => \@type_constraints );
182134e8 95}
a15dff8d 96
0c015f1b 97sub create_parameterized_type_constraint {
d9b40005 98 my $type_constraint_name = shift;
180899ed 99 my ( $base_type, $type_parameter )
100 = _parse_parameterized_type_constraint($type_constraint_name);
e85d2a5d 101
180899ed 102 ( defined $base_type && defined $type_parameter )
103 || __PACKAGE__->_throw_error(
104 "Could not parse type name ($type_constraint_name) correctly");
e85d2a5d 105
180899ed 106 if ( $REGISTRY->has_type_constraint($base_type) ) {
90e78884 107 my $base_type_tc = $REGISTRY->get_type_constraint($base_type);
108 return _create_parameterized_type_constraint(
109 $base_type_tc,
110 $type_parameter
111 );
180899ed 112 }
113 else {
114 __PACKAGE__->_throw_error(
115 "Could not locate the base type ($base_type)");
90e78884 116 }
22aed3c0 117}
118
90e78884 119sub _create_parameterized_type_constraint {
120 my ( $base_type_tc, $type_parameter ) = @_;
121 if ( $base_type_tc->can('parameterize') ) {
122 return $base_type_tc->parameterize($type_parameter);
180899ed 123 }
124 else {
90e78884 125 return Moose::Meta::TypeConstraint::Parameterized->new(
180899ed 126 name => $base_type_tc->name . '[' . $type_parameter . ']',
90e78884 127 parent => $base_type_tc,
180899ed 128 type_parameter =>
129 find_or_create_isa_type_constraint($type_parameter),
90e78884 130 );
131 }
180899ed 132}
90e78884 133
4ab662d6 134#should we also support optimized checks?
0c015f1b 135sub create_class_type_constraint {
620db045 136 my ( $class, $options ) = @_;
137
180899ed 138# too early for this check
139#find_type_constraint("ClassName")->check($class)
140# || __PACKAGE__->_throw_error("Can't create a class type constraint because '$class' is not a class name");
3fef8ce8 141
620db045 142 my %options = (
143 class => $class,
144 name => $class,
145 %{ $options || {} },
4ab662d6 146 );
620db045 147
148 $options{name} ||= "__ANON__";
149
180899ed 150 Moose::Meta::TypeConstraint::Class->new(%options);
3fef8ce8 151}
152
0c015f1b 153sub create_role_type_constraint {
620db045 154 my ( $role, $options ) = @_;
e85d2a5d 155
180899ed 156# too early for this check
157#find_type_constraint("ClassName")->check($class)
158# || __PACKAGE__->_throw_error("Can't create a class type constraint because '$class' is not a class name");
e85d2a5d 159
620db045 160 my %options = (
161 role => $role,
162 name => $role,
163 %{ $options || {} },
164 );
e85d2a5d 165
620db045 166 $options{name} ||= "__ANON__";
167
180899ed 168 Moose::Meta::TypeConstraint::Role->new(%options);
620db045 169}
170
0c015f1b 171sub find_or_create_type_constraint {
620db045 172 my ( $type_constraint_name, $options_for_anon_type ) = @_;
173
180899ed 174 if ( my $constraint
175 = find_or_parse_type_constraint($type_constraint_name) ) {
620db045 176 return $constraint;
d9b40005 177 }
620db045 178 elsif ( defined $options_for_anon_type ) {
180899ed 179
d9b40005 180 # NOTE:
4ab662d6 181 # if there is no $options_for_anon_type
182 # specified, then we assume they don't
f3c4e20e 183 # want to create one, and return nothing.
f3c4e20e 184
d9b40005 185 # otherwise assume that we should create
e85d2a5d 186 # an ANON type with the $options_for_anon_type
d9b40005 187 # options which can be passed in. It should
e85d2a5d 188 # be noted that these don't get registered
d9b40005 189 # so we need to return it.
190 # - SL
191 return Moose::Meta::TypeConstraint->new(
192 name => '__ANON__',
e85d2a5d 193 %{$options_for_anon_type}
d9b40005 194 );
195 }
e85d2a5d 196
620db045 197 return;
198}
199
0c015f1b 200sub find_or_create_isa_type_constraint {
620db045 201 my $type_constraint_name = shift;
180899ed 202 find_or_parse_type_constraint($type_constraint_name)
203 || create_class_type_constraint($type_constraint_name);
620db045 204}
205
0c015f1b 206sub find_or_create_does_type_constraint {
620db045 207 my $type_constraint_name = shift;
180899ed 208 find_or_parse_type_constraint($type_constraint_name)
209 || create_role_type_constraint($type_constraint_name);
620db045 210}
211
0c015f1b 212sub find_or_parse_type_constraint {
eb4c4e82 213 my $type_constraint_name = normalize_type_constraint_name(shift);
620db045 214 my $constraint;
180899ed 215
216 if ( $constraint = find_type_constraint($type_constraint_name) ) {
e606ae5f 217 return $constraint;
180899ed 218 }
219 elsif ( _detect_type_constraint_union($type_constraint_name) ) {
620db045 220 $constraint = create_type_constraint_union($type_constraint_name);
180899ed 221 }
222 elsif ( _detect_parameterized_type_constraint($type_constraint_name) ) {
223 $constraint
224 = create_parameterized_type_constraint($type_constraint_name);
225 }
226 else {
620db045 227 return;
228 }
bb6c8335 229
d9b40005 230 $REGISTRY->add_type_constraint($constraint);
e85d2a5d 231 return $constraint;
d9b40005 232}
22aed3c0 233
eb4c4e82 234sub normalize_type_constraint_name {
84a9c64c 235 my $type_constraint_name = shift;
c8f663b2 236 $type_constraint_name =~ s/\s//g;
eb4c4e82 237 return $type_constraint_name;
238}
239
5f223879 240sub _confess {
241 my $error = shift;
242
243 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
244 Carp::confess($error);
245}
246
22aed3c0 247## --------------------------------------------------------
248## exported functions ...
249## --------------------------------------------------------
250
0c015f1b 251sub find_type_constraint {
eeedfc8a 252 my $type = shift;
253
254 if ( blessed $type and $type->isa("Moose::Meta::TypeConstraint") ) {
255 return $type;
e606ae5f 256 }
257 else {
258 return unless $REGISTRY->has_type_constraint($type);
eeedfc8a 259 return $REGISTRY->get_type_constraint($type);
260 }
261}
22aed3c0 262
0c015f1b 263sub register_type_constraint {
3fef8ce8 264 my $constraint = shift;
180899ed 265 __PACKAGE__->_throw_error("can't register an unnamed type constraint")
266 unless defined $constraint->name;
3fef8ce8 267 $REGISTRY->add_type_constraint($constraint);
dabed765 268 return $constraint;
3fef8ce8 269}
270
7c13858b 271# type constructors
a15dff8d 272
9c27968f 273sub type {
180899ed 274
9e856c83 275 # back-compat version, called without sugar
180899ed 276 if ( !any { ( reftype($_) || '' ) eq 'HASH' } @_ ) {
9e856c83 277 return _create_type_constraint( $_[0], undef, $_[1] );
9a63faba 278 }
9a63faba 279
9e856c83 280 my $name = shift;
9a63faba 281
9e856c83 282 my %p = map { %{$_} } @_;
283
180899ed 284 return _create_type_constraint(
285 $name, undef, $p{where}, $p{message},
286 $p{optimize_as}
287 );
a15dff8d 288}
289
9c27968f 290sub subtype {
180899ed 291
9a63faba 292 # crazy back-compat code for being called without sugar ...
e3979c3e 293 #
9a63faba 294 # subtype 'Parent', sub { where };
295 if ( scalar @_ == 2 && ( reftype( $_[1] ) || '' ) eq 'CODE' ) {
296 return _create_type_constraint( undef, @_ );
297 }
298
299 # subtype 'Parent', sub { where }, sub { message };
300 # subtype 'Parent', sub { where }, sub { message }, sub { optimized };
301 if ( scalar @_ >= 3 && all { ( reftype($_) || '' ) eq 'CODE' }
180899ed 302 @_[ 1 .. $#_ ] ) {
9a63faba 303 return _create_type_constraint( undef, @_ );
304 }
305
306 # subtype 'Name', 'Parent', ...
307 if ( scalar @_ >= 2 && all { !ref } @_[ 0, 1 ] ) {
308 return _create_type_constraint(@_);
309 }
310
180899ed 311 if ( @_ == 1 && !ref $_[0] ) {
312 __PACKAGE__->_throw_error(
313 'A subtype cannot consist solely of a name, it must have a parent'
314 );
f75f625d 315 }
316
f6c0c589 317 # The blessed check is mostly to accommodate MooseX::Types, which
318 # uses an object which overloads stringification as a type name.
180899ed 319 my $name = ref $_[0] && !blessed $_[0] ? undef : shift;
9a63faba 320
321 my %p = map { %{$_} } @_;
322
323 # subtype Str => where { ... };
180899ed 324 if ( !exists $p{as} ) {
9e856c83 325 $p{as} = $name;
9a63faba 326 $name = undef;
327 }
328
180899ed 329 return _create_type_constraint(
330 $name, $p{as}, $p{where}, $p{message},
331 $p{optimize_as}
332 );
a15dff8d 333}
334
9c27968f 335sub class_type {
4ab662d6 336 register_type_constraint(
337 create_class_type_constraint(
338 $_[0],
180899ed 339 ( defined( $_[1] ) ? $_[1] : () ),
4ab662d6 340 )
341 );
3fef8ce8 342}
343
620db045 344sub role_type ($;$) {
345 register_type_constraint(
346 create_role_type_constraint(
347 $_[0],
180899ed 348 ( defined( $_[1] ) ? $_[1] : () ),
620db045 349 )
350 );
351}
352
1b2c9bda 353sub maybe_type {
354 my ($type_parameter) = @_;
355
28ce1444 356 register_type_constraint(
ed7060d9 357 $REGISTRY->get_type_constraint('Maybe')->parameterize($type_parameter)
28ce1444 358 );
1b2c9bda 359}
360
180899ed 361sub duck_type {
cdacfaf3 362 my ( $type_name, @methods ) = @_;
180899ed 363 if ( ref $type_name eq 'ARRAY' && !@methods ) {
cdacfaf3 364 @methods = @$type_name;
180899ed 365 $type_name = undef;
366 }
367
368 register_type_constraint(
369 _create_type_constraint(
cdacfaf3 370 $type_name,
371 'Object',
180899ed 372 sub {
373 my $obj = $_;
58936059 374 my $class = blessed($obj) || return;
375 return if $class eq 'Regexp';
21e16327 376 return 0 unless all { $obj->can($_) } @methods;
cdacfaf3 377 return 1;
180899ed 378 },
379 sub {
380 my $obj = $_;
58936059 381 my $class = blessed($obj);
180899ed 382 my @missing_methods = grep { !$obj->can($_) } @methods;
383 return
58936059 384 "$class is missing methods '@missing_methods'";
180899ed 385 },
386 )
387 );
388}
389
9c27968f 390sub coerce {
180899ed 391 my ( $type_name, @coercion_map ) = @_;
392 _install_type_coercions( $type_name, \@coercion_map );
182134e8 393}
394
f6c0c589 395# The trick of returning @_ lets us avoid having to specify a
396# prototype. Perl will parse this:
397#
398# subtype 'Foo'
399# => as 'Str'
400# => where { ... }
401#
402# as this:
403#
404# subtype( 'Foo', as( 'Str', where { ... } ) );
405#
406# If as() returns all it's extra arguments, this just works, and
407# preserves backwards compatibility.
180899ed 408sub as { { as => shift }, @_ }
9e856c83 409sub where (&) { { where => $_[0] } }
410sub message (&) { { message => $_[0] } }
411sub optimize_as (&) { { optimize_as => $_[0] } }
8ecb1fa0 412
9a63faba 413sub from {@_}
414sub via (&) { $_[0] }
a15dff8d 415
9c27968f 416sub enum {
180899ed 417 my ( $type_name, @values ) = @_;
418
4ab662d6 419 # NOTE:
420 # if only an array-ref is passed then
9f4334a1 421 # you get an anon-enum
422 # - SL
180899ed 423 if ( ref $type_name eq 'ARRAY' && !@values ) {
9f4334a1 424 @values = @$type_name;
425 $type_name = undef;
426 }
180899ed 427 ( scalar @values >= 2 )
428 || __PACKAGE__->_throw_error(
429 "You must have at least two values to enumerate through");
c4fe165f 430 my %valid = map { $_ => 1 } @values;
dabed765 431
432 register_type_constraint(
433 create_enum_type_constraint(
434 $type_name,
435 \@values,
436 )
437 );
438}
439
0c015f1b 440sub create_enum_type_constraint {
dabed765 441 my ( $type_name, $values ) = @_;
e606ae5f 442
dabed765 443 Moose::Meta::TypeConstraint::Enum->new(
180899ed 444 name => $type_name || '__ANON__',
dabed765 445 values => $values,
a0f8153d 446 );
fcec2383 447}
448
d9b40005 449## --------------------------------------------------------
450## desugaring functions ...
451## --------------------------------------------------------
452
e85d2a5d 453sub _create_type_constraint ($$$;$$) {
9a63faba 454 my $name = shift;
455 my $parent = shift;
456 my $check = shift;
457 my $message = shift;
458 my $optimized = shift;
d9b40005 459
9a63faba 460 my $pkg_defined_in = scalar( caller(1) );
e85d2a5d 461
1da6728b 462 if ( defined $name ) {
d9b40005 463 my $type = $REGISTRY->get_type_constraint($name);
e85d2a5d 464
5f223879 465 ( $type->_package_defined_in eq $pkg_defined_in )
466 || _confess(
467 "The type constraint '$name' has already been created in "
468 . $type->_package_defined_in
469 . " and cannot be created again in "
470 . $pkg_defined_in )
471 if defined $type;
eee1a213 472
473 $name =~ /^[\w:\.]+$/
474 or die qq{$name contains invalid characters for a type name.}
33c8a6d0 475 . qq{ Names can contain alphanumeric character, ":", and "."\n};
e85d2a5d 476 }
1da6728b 477
9ceb576e 478 my %opts = (
9a63faba 479 name => $name,
d9b40005 480 package_defined_in => $pkg_defined_in,
e85d2a5d 481
1da6728b 482 ( $check ? ( constraint => $check ) : () ),
483 ( $message ? ( message => $message ) : () ),
484 ( $optimized ? ( optimized => $optimized ) : () ),
d9b40005 485 );
1da6728b 486
9ceb576e 487 my $constraint;
180899ed 488 if (
489 defined $parent
1da6728b 490 and $parent
180899ed 491 = blessed $parent
492 ? $parent
493 : find_or_create_isa_type_constraint($parent)
494 ) {
85a9908f 495 $constraint = $parent->create_child_type(%opts);
1da6728b 496 }
497 else {
498 $constraint = Moose::Meta::TypeConstraint->new(%opts);
4ab662d6 499 }
d9b40005 500
501 $REGISTRY->add_type_constraint($constraint)
502 if defined $name;
503
504 return $constraint;
505}
506
e85d2a5d 507sub _install_type_coercions ($$) {
180899ed 508 my ( $type_name, $coercion_map ) = @_;
e606ae5f 509 my $type = find_type_constraint($type_name);
180899ed 510 ( defined $type )
511 || __PACKAGE__->_throw_error(
a885c019 512 "Cannot find type '$type_name', perhaps you forgot to load it");
180899ed 513 if ( $type->has_coercion ) {
41e007e4 514 $type->coercion->add_type_coercions(@$coercion_map);
515 }
516 else {
517 my $type_coercion = Moose::Meta::TypeCoercion->new(
518 type_coercion_map => $coercion_map,
519 type_constraint => $type
520 );
521 $type->coercion($type_coercion);
522 }
d9b40005 523}
524
525## --------------------------------------------------------
f1917f58 526## type notation parsing ...
527## --------------------------------------------------------
528
529{
180899ed 530
e85d2a5d 531 # All I have to say is mugwump++ cause I know
532 # do not even have enough regexp-fu to be able
533 # to have written this (I can only barely
f1917f58 534 # understand it as it is)
e85d2a5d 535 # - SL
536
f1917f58 537 use re "eval";
538
eee1a213 539 my $valid_chars = qr{[\w:\.]};
f1917f58 540 my $type_atom = qr{ $valid_chars+ };
541
be722745 542 my $any;
543
180899ed 544 my $type = qr{ $valid_chars+ (?: \[ \s* (??{$any}) \s* \] )? }x;
545 my $type_capture_parts
546 = qr{ ($valid_chars+) (?: \[ \s* ((??{$any})) \s* \] )? }x;
547 my $type_with_parameter
548 = qr{ $valid_chars+ \[ \s* (??{$any}) \s* \] }x;
f1917f58 549
3796382a 550 my $op_union = qr{ \s* \| \s* }x;
f1917f58 551 my $union = qr{ $type (?: $op_union $type )+ }x;
552
84a9c64c 553 $any = qr{ $type | $union }x;
f1917f58 554
0fbd4b0a 555 sub _parse_parameterized_type_constraint {
180899ed 556 { no warnings 'void'; $any; } # force capture of interpolated lexical
84a9c64c 557 $_[0] =~ m{ $type_capture_parts }x;
180899ed 558 return ( $1, $2 );
f1917f58 559 }
560
0fbd4b0a 561 sub _detect_parameterized_type_constraint {
180899ed 562 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 563 $_[0] =~ m{ ^ $type_with_parameter $ }x;
f1917f58 564 }
565
566 sub _parse_type_constraint_union {
180899ed 567 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 568 my $given = shift;
569 my @rv;
570 while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) {
82a5b1a7 571 push @rv => $1;
e85d2a5d 572 }
180899ed 573 ( pos($given) eq length($given) )
574 || __PACKAGE__->_throw_error( "'$given' didn't parse (parse-pos="
575 . pos($given)
576 . " and str-length="
577 . length($given)
578 . ")" );
e85d2a5d 579 @rv;
f1917f58 580 }
581
582 sub _detect_type_constraint_union {
180899ed 583 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 584 $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x;
f1917f58 585 }
586}
587
588## --------------------------------------------------------
d9b40005 589# define some basic built-in types
590## --------------------------------------------------------
a15dff8d 591
3cae4250 592# By making these classes immutable before creating all the types we
593# below, we avoid repeatedly calling the slow MOP-based accessors.
594$_->make_immutable(
595 inline_constructor => 1,
596 constructor_name => "_new",
597
598 # these are Class::MOP accessors, so they need inlining
599 inline_accessors => 1
600 ) for grep { $_->is_mutable }
37edf27e 601 map { Class::MOP::class_of($_) }
3cae4250 602 qw(
603 Moose::Meta::TypeConstraint
604 Moose::Meta::TypeConstraint::Union
605 Moose::Meta::TypeConstraint::Parameterized
606 Moose::Meta::TypeConstraint::Parameterizable
607 Moose::Meta::TypeConstraint::Class
608 Moose::Meta::TypeConstraint::Role
609 Moose::Meta::TypeConstraint::Enum
610 Moose::Meta::TypeConstraint::Registry
611);
612
180899ed 613type 'Any' => where {1}; # meta-type including all
3054a5c9 614subtype 'Item' => as 'Any'; # base-type
a15dff8d 615
fd542f49 616subtype 'Undef' => as 'Item' => where { !defined($_) };
180899ed 617subtype 'Defined' => as 'Item' => where { defined($_) };
618
619subtype 'Bool' => as 'Item' =>
620 where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
621
622subtype 'Value' => as 'Defined' => where { !ref($_) } =>
623 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Value;
624
625subtype 'Ref' => as 'Defined' => where { ref($_) } =>
626 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Ref;
627
628subtype 'Str' => as 'Value' => where {1} =>
629 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Str;
630
c29e3978 631subtype 'Num' => as 'Str' =>
180899ed 632 where { Scalar::Util::looks_like_number($_) } =>
633 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Num;
634
635subtype 'Int' => as 'Num' => where { "$_" =~ /^-?[0-9]+$/ } =>
636 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Int;
637
638subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } =>
639 optimize_as
640 \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef;
641subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } =>
642 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::CodeRef;
643subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } =>
644 optimize_as
645 \&Moose::Util::TypeConstraints::OptimizedConstraints::RegexpRef;
646subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } =>
647 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::GlobRef;
a15dff8d 648
0a5bd159 649# NOTE:
e85d2a5d 650# scalar filehandles are GLOB refs,
0a5bd159 651# but a GLOB ref is not always a filehandle
180899ed 652subtype 'FileHandle' => as 'GlobRef' => where {
653 Scalar::Util::openhandle($_) || ( blessed($_) && $_->isa("IO::Handle") );
654} => optimize_as
655 \&Moose::Util::TypeConstraints::OptimizedConstraints::FileHandle;
0a5bd159 656
e85d2a5d 657# NOTE:
a15dff8d 658# blessed(qr/.../) returns true,.. how odd
180899ed 659subtype 'Object' => as 'Ref' =>
660 where { blessed($_) && blessed($_) ne 'Regexp' } =>
661 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Object;
a15dff8d 662
180899ed 663subtype 'Role' => as 'Object' => where { $_->can('does') } =>
664 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Role;
e85d2a5d 665
180899ed 666my $_class_name_checker = sub { };
0e0709ea 667
180899ed 668subtype 'ClassName' => as 'Str' =>
669 where { Class::MOP::is_class_loaded($_) } => optimize_as
670 \&Moose::Util::TypeConstraints::OptimizedConstraints::ClassName;
02a0fb52 671
180899ed 672subtype 'RoleName' => as 'ClassName' => where {
6b885dfa 673 (Class::MOP::class_of($_) || return)->isa('Moose::Meta::Role');
180899ed 674} => optimize_as
675 \&Moose::Util::TypeConstraints::OptimizedConstraints::RoleName;
f0cac16f 676
d9b40005 677## --------------------------------------------------------
7e4e1ad4 678# parameterizable types ...
679
680$REGISTRY->add_type_constraint(
681 Moose::Meta::TypeConstraint::Parameterizable->new(
180899ed 682 name => 'ArrayRef',
683 package_defined_in => __PACKAGE__,
684 parent => find_type_constraint('Ref'),
685 constraint => sub { ref($_) eq 'ARRAY' },
686 optimized =>
687 \&Moose::Util::TypeConstraints::OptimizedConstraints::ArrayRef,
7e4e1ad4 688 constraint_generator => sub {
689 my $type_parameter = shift;
180899ed 690 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 691 return sub {
692 foreach my $x (@$_) {
180899ed 693 ( $check->($x) ) || return;
694 }
695 1;
696 }
7e4e1ad4 697 }
698 )
699);
700
701$REGISTRY->add_type_constraint(
702 Moose::Meta::TypeConstraint::Parameterizable->new(
180899ed 703 name => 'HashRef',
704 package_defined_in => __PACKAGE__,
705 parent => find_type_constraint('Ref'),
706 constraint => sub { ref($_) eq 'HASH' },
707 optimized =>
708 \&Moose::Util::TypeConstraints::OptimizedConstraints::HashRef,
7e4e1ad4 709 constraint_generator => sub {
4ab662d6 710 my $type_parameter = shift;
180899ed 711 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 712 return sub {
180899ed 713 foreach my $x ( values %$_ ) {
714 ( $check->($x) ) || return;
715 }
716 1;
717 }
7e4e1ad4 718 }
719 )
720);
721
722$REGISTRY->add_type_constraint(
723 Moose::Meta::TypeConstraint::Parameterizable->new(
724 name => 'Maybe',
725 package_defined_in => __PACKAGE__,
726 parent => find_type_constraint('Item'),
180899ed 727 constraint => sub {1},
7e4e1ad4 728 constraint_generator => sub {
4ab662d6 729 my $type_parameter = shift;
180899ed 730 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 731 return sub {
180899ed 732 return 1 if not( defined($_) ) || $check->($_);
7e4e1ad4 733 return;
180899ed 734 }
7e4e1ad4 735 }
736 )
737);
738
180899ed 739my @PARAMETERIZABLE_TYPES
740 = map { $REGISTRY->get_type_constraint($_) } qw[ArrayRef HashRef Maybe];
741
742sub get_all_parameterizable_types {@PARAMETERIZABLE_TYPES}
7e4e1ad4 743
4ab662d6 744sub add_parameterizable_type {
7e4e1ad4 745 my $type = shift;
180899ed 746 ( blessed $type
747 && $type->isa('Moose::Meta::TypeConstraint::Parameterizable') )
748 || __PACKAGE__->_throw_error(
749 "Type must be a Moose::Meta::TypeConstraint::Parameterizable not $type"
750 );
7e4e1ad4 751 push @PARAMETERIZABLE_TYPES => $type;
4ab662d6 752}
7e4e1ad4 753
754## --------------------------------------------------------
d9b40005 755# end of built-in types ...
756## --------------------------------------------------------
757
943596a6 758{
759 my @BUILTINS = list_all_type_constraints();
180899ed 760 sub list_all_builtin_type_constraints {@BUILTINS}
943596a6 761}
762
6ea98933 763sub _throw_error {
6b83828f 764 shift;
6ea98933 765 require Moose;
766 unshift @_, 'Moose';
767 goto &Moose::throw_error;
768}
769
a15dff8d 7701;
771
772__END__
773
774=pod
775
776=head1 NAME
777
e522431d 778Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 779
780=head1 SYNOPSIS
781
782 use Moose::Util::TypeConstraints;
783
e85d2a5d 784 subtype 'Natural'
e606ae5f 785 => as 'Int'
a15dff8d 786 => where { $_ > 0 };
e85d2a5d 787
788 subtype 'NaturalLessThanTen'
2c0cbef7 789 => as 'Natural'
79592a54 790 => where { $_ < 10 }
791 => message { "This number ($_) is not less than ten!" };
e85d2a5d 792
793 coerce 'Num'
2c0cbef7 794 => from 'Str'
e85d2a5d 795 => via { 0+$_ };
796
2c0cbef7 797 enum 'RGBColors' => qw(red green blue);
a15dff8d 798
e7fcb7b2 799 no Moose::Util::TypeConstraints;
800
a15dff8d 801=head1 DESCRIPTION
802
e85d2a5d 803This module provides Moose with the ability to create custom type
6549b0d1 804constraints to be used in attribute definition.
e522431d 805
6ba6d68c 806=head2 Important Caveat
807
e85d2a5d 808This is B<NOT> a type system for Perl 5. These are type constraints,
809and they are not used by Moose unless you tell it to. No type
e7fcb7b2 810inference is performed, expressions are not typed, etc. etc. etc.
6ba6d68c 811
e7fcb7b2 812A type constraint is at heart a small "check if a value is valid"
813function. A constraint can be associated with an attribute. This
814simplifies parameter validation, and makes your code clearer to read,
815because you can refer to constraints by name.
6ba6d68c 816
2c0cbef7 817=head2 Slightly Less Important Caveat
818
e7fcb7b2 819It is B<always> a good idea to quote your type names.
004222dc 820
e7fcb7b2 821This prevents Perl from trying to execute the call as an indirect
822object call. This can be an issue when you have a subtype with the
823same name as a valid class.
2c0cbef7 824
e7fcb7b2 825For instance:
e85d2a5d 826
2c0cbef7 827 subtype DateTime => as Object => where { $_->isa('DateTime') };
828
e7fcb7b2 829will I<just work>, while this:
2c0cbef7 830
831 use DateTime;
832 subtype DateTime => as Object => where { $_->isa('DateTime') };
833
e85d2a5d 834will fail silently and cause many headaches. The simple way to solve
835this, as well as future proof your subtypes from classes which have
e7fcb7b2 836yet to have been created, is to quote the type name:
2c0cbef7 837
838 use DateTime;
d44714be 839 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 840
6ba6d68c 841=head2 Default Type Constraints
e522431d 842
e606ae5f 843This module also provides a simple hierarchy for Perl 5 types, here is
004222dc 844that hierarchy represented visually.
e522431d 845
846 Any
e85d2a5d 847 Item
5a4c5493 848 Bool
7e4e1ad4 849 Maybe[`a]
f65cb534 850 Undef
851 Defined
5a4c5493 852 Value
853 Num
854 Int
855 Str
9af1d28b 856 ClassName
ed87d4fd 857 RoleName
5a4c5493 858 Ref
859 ScalarRef
7e4e1ad4 860 ArrayRef[`a]
861 HashRef[`a]
5a4c5493 862 CodeRef
863 RegexpRef
3f7376b0 864 GlobRef
0a5bd159 865 FileHandle
e85d2a5d 866 Object
2cbb5233 867 Role
e522431d 868
4ab662d6 869B<NOTE:> Any type followed by a type parameter C<[`a]> can be
7e4e1ad4 870parameterized, this means you can say:
871
757e07ef 872 ArrayRef[Int] # an array of integers
7e4e1ad4 873 HashRef[CodeRef] # a hash of str to CODE ref mappings
874 Maybe[Str] # value may be a string, may be undefined
875
4e8a0f64 876If Moose finds a name in brackets that it does not recognize as an
877existing type, it assumes that this is a class name, for example
878C<ArrayRef[DateTime]>.
879
e7fcb7b2 880B<NOTE:> Unless you parameterize a type, then it is invalid to include
881the square brackets. I.e. C<ArrayRef[]> will be treated as a new type
882name, I<not> as a parameterization of C<ArrayRef>.
e606ae5f 883
4ab662d6 884B<NOTE:> The C<Undef> type constraint for the most part works
885correctly now, but edge cases may still exist, please use it
6549b0d1 886sparingly.
703e92fb 887
7e4e1ad4 888B<NOTE:> The C<ClassName> type constraint does a complex package
e7fcb7b2 889existence check. This means that your class B<must> be loaded for this
890type constraint to pass.
9af1d28b 891
e7fcb7b2 892B<NOTE:> The C<RoleName> constraint checks a string is a I<package
893name> which is a role, like C<'MyApp::Role::Comparable'>. The C<Role>
894constraint checks that an I<object does> the named role.
ed87d4fd 895
e606ae5f 896=head2 Type Constraint Naming
004222dc 897
eee1a213 898Type name declared via this module can only contain alphanumeric
899characters, colons (:), and periods (.).
900
e606ae5f 901Since the types created by this module are global, it is suggested
902that you namespace your types just as you would namespace your
e7fcb7b2 903modules. So instead of creating a I<Color> type for your
904B<My::Graphics> module, you would call the type
905I<My::Graphics::Types::Color> instead.
004222dc 906
703e92fb 907=head2 Use with Other Constraint Modules
908
e7fcb7b2 909This module can play nicely with other constraint modules with some
910slight tweaking. The C<where> clause in types is expected to be a
911C<CODE> reference which checks it's first argument and returns a
912boolean. Since most constraint modules work in a similar way, it
913should be simple to adapt them to work with Moose.
703e92fb 914
e85d2a5d 915For instance, this is how you could use it with
916L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 917
9e856c83 918 type 'HashOfArrayOfObjects',
919 {
920 where => IsHashRef(
703e92fb 921 -keys => HasLength,
9e856c83 922 -values => IsArrayRef(IsObject)
923 )
924 };
703e92fb 925
e7fcb7b2 926For more examples see the F<t/200_examples/004_example_w_DCS.t> test
927file.
703e92fb 928
e85d2a5d 929Here is an example of using L<Test::Deep> and it's non-test
930related C<eq_deeply> function.
703e92fb 931
e85d2a5d 932 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 933 => where {
e85d2a5d 934 eq_deeply($_,
703e92fb 935 array_each(subhashof({
936 bar => isa('Bar'),
937 random_number => ignore()
e85d2a5d 938 })))
703e92fb 939 };
940
e606ae5f 941For a complete example see the
e7fcb7b2 942F<t/200_examples/005_example_w_TestDeep.t> test file.
e85d2a5d 943
a15dff8d 944=head1 FUNCTIONS
945
946=head2 Type Constraint Constructors
947
e7fcb7b2 948The following functions are used to create type constraints. They
949will also register the type constraints your create in a global
950registry that is used to look types up by name.
a15dff8d 951
25f2c3fc 952See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 953
6ba6d68c 954=over 4
a15dff8d 955
fbe1e4a5 956=item B<< subtype 'Name' => as 'Parent' => where { } ... >>
182134e8 957
e85d2a5d 958This creates a named subtype.
d6e2d9a1 959
dba9208a 960If you provide a parent that Moose does not recognize, it will
961automatically create a new class type constraint for this name.
962
9e856c83 963When creating a named type, the C<subtype> function should either be
964called with the sugar helpers (C<where>, C<message>, etc), or with a
965name and a hashref of parameters:
966
967 subtype( 'Foo', { where => ..., message => ... } );
968
969The valid hashref keys are C<as> (the parent), C<where>, C<message>,
970and C<optimize_as>.
9a63faba 971
fbe1e4a5 972=item B<< subtype as 'Parent' => where { } ... >>
182134e8 973
e85d2a5d 974This creates an unnamed subtype and will return the type
975constraint meta-object, which will be an instance of
976L<Moose::Meta::TypeConstraint>.
a15dff8d 977
9e856c83 978When creating an anonymous type, the C<subtype> function should either
979be called with the sugar helpers (C<where>, C<message>, etc), or with
980just a hashref of parameters:
981
982 subtype( { where => ..., message => ... } );
983
620db045 984=item B<class_type ($class, ?$options)>
3fef8ce8 985
ed87d4fd 986Creates a new subtype of C<Object> with the name C<$class> and the
987metaclass L<Moose::Meta::TypeConstraint::Class>.
3fef8ce8 988
620db045 989=item B<role_type ($role, ?$options)>
990
ed87d4fd 991Creates a C<Role> type constraint with the name C<$role> and the
992metaclass L<Moose::Meta::TypeConstraint::Role>.
620db045 993
1b2c9bda 994=item B<maybe_type ($type)>
995
996Creates a type constraint for either C<undef> or something of the
997given type.
998
e451e855 999=item B<duck_type ($name, @methods)>
1000
88b68372 1001This will create a subtype of Object and test to make sure the value
1002C<can()> do the methods in C<@methods>.
1003
1004This is intended as an easy way to accept non-Moose objects that
1005provide a certain interface. If you're using Moose classes, we
1006recommend that you use a C<requires>-only Role instead.
e451e855 1007
1008=item B<duck_type (\@methods)>
1009
88b68372 1010If passed an ARRAY reference instead of the C<$name>, C<@methods>
1011pair, this will create an unnamed duck type. This can be used in an
91aecfa0 1012attribute definition like so:
e451e855 1013
88b68372 1014 has 'cache' => (
1015 is => 'ro',
1016 isa => duck_type( [qw( get_set )] ),
1017 );
e451e855 1018
fcec2383 1019=item B<enum ($name, @values)>
1020
e85d2a5d 1021This will create a basic subtype for a given set of strings.
1022The resulting constraint will be a subtype of C<Str> and
4ce56d04 1023will match any of the items in C<@values>. It is case sensitive.
1024See the L<SYNOPSIS> for a simple example.
2c0cbef7 1025
6549b0d1 1026B<NOTE:> This is not a true proper enum type, it is simply
1027a convenient constraint builder.
2c0cbef7 1028
9f4334a1 1029=item B<enum (\@values)>
1030
4ab662d6 1031If passed an ARRAY reference instead of the C<$name>, C<@values> pair,
9f4334a1 1032this will create an unnamed enum. This can then be used in an attribute
1033definition like so:
1034
1035 has 'sort_order' => (
1036 is => 'ro',
4ab662d6 1037 isa => enum([qw[ ascending descending ]]),
9f4334a1 1038 );
1039
e7fcb7b2 1040=item B<as 'Parent'>
a15dff8d 1041
6ba6d68c 1042This is just sugar for the type constraint construction syntax.
a15dff8d 1043
e7fcb7b2 1044It takes a single argument, which is the name of a parent type.
1045
1046=item B<where { ... }>
a15dff8d 1047
6ba6d68c 1048This is just sugar for the type constraint construction syntax.
76d37e5a 1049
e7fcb7b2 1050It takes a subroutine reference as an argument. When the type
1051constraint is tested, the reference is run with the value to be tested
1052in C<$_>. This reference should return true or false to indicate
1053whether or not the constraint check passed.
e606ae5f 1054
e7fcb7b2 1055=item B<message { ... }>
76d37e5a 1056
1057This is just sugar for the type constraint construction syntax.
a15dff8d 1058
e7fcb7b2 1059It takes a subroutine reference as an argument. When the type
1060constraint fails, then the code block is run with the value provided
1061in C<$_>. This reference should return a string, which will be used in
1062the text of the exception thrown.
e606ae5f 1063
e7fcb7b2 1064=item B<optimize_as { ... }>
8ecb1fa0 1065
e85d2a5d 1066This can be used to define a "hand optimized" version of your
d44714be 1067type constraint which can be used to avoid traversing a subtype
6549b0d1 1068constraint hierarchy.
d44714be 1069
e85d2a5d 1070B<NOTE:> You should only use this if you know what you are doing,
1071all the built in types use this, so your subtypes (assuming they
d44714be 1072are shallow) will not likely need to use this.
1073
e7fcb7b2 1074=item B<type 'Name' => where { } ... >
1075
1076This creates a base type, which has no parent.
1077
1078The C<type> function should either be called with the sugar helpers
1079(C<where>, C<message>, etc), or with a name and a hashref of
1080parameters:
1081
1082 type( 'Foo', { where => ..., message => ... } );
1083
1084The valid hashref keys are C<where>, C<message>, and C<optimize_as>.
1085
6ba6d68c 1086=back
a15dff8d 1087
6ba6d68c 1088=head2 Type Coercion Constructors
a15dff8d 1089
e7fcb7b2 1090You can define coercions for type constraints, which allow you to
1091automatically transform values to something valid for the type
1092constraint. If you ask your accessor to coerce, then Moose will run
1093the type-coercion code first, followed by the type constraint
1094check. This feature should be used carefully as it is very powerful
1095and could easily take off a limb if you are not careful.
a15dff8d 1096
25f2c3fc 1097See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 1098
6ba6d68c 1099=over 4
a15dff8d 1100
e7fcb7b2 1101=item B<< coerce 'Name' => from 'OtherName' => via { ... } >>
a15dff8d 1102
e7fcb7b2 1103This defines a coercion from one type to another. The C<Name> argument
1104is the type you are coercing I<to>.
1105
1106=item B<from 'OtherName'>
a15dff8d 1107
6ba6d68c 1108This is just sugar for the type coercion construction syntax.
1109
e7fcb7b2 1110It takes a single type name (or type object), which is the type being
1111coerced I<from>.
1112
1113=item B<via { ... }>
a15dff8d 1114
6ba6d68c 1115This is just sugar for the type coercion construction syntax.
a15dff8d 1116
e7fcb7b2 1117It takes a subroutine reference. This reference will be called with
1118the value to be coerced in C<$_>. It is expected to return a new value
1119of the proper type for the coercion.
1120
a15dff8d 1121=back
1122
e7fcb7b2 1123=head2 Creating and Finding Type Constraints
1124
1125These are additional functions for creating and finding type
1126constraints. Most of these functions are not available for
1127importing. The ones that are importable as specified.
004222dc 1128
1129=over 4
1130
e7fcb7b2 1131=item B<find_type_constraint($type_name)>
eb4c4e82 1132
e7fcb7b2 1133This function can be used to locate the L<Moose::Meta::TypeConstraint>
1134object for a named type.
eb4c4e82 1135
e7fcb7b2 1136This function is importable.
004222dc 1137
e7fcb7b2 1138=item B<register_type_constraint($type_object)>
004222dc 1139
e7fcb7b2 1140This function will register a L<Moose::Meta::TypeConstraint> with the
1141global type registry.
004222dc 1142
e7fcb7b2 1143This function is importable.
004222dc 1144
e7fcb7b2 1145=item B<normalize_type_constraint_name($type_constraint_name)>
004222dc 1146
e7fcb7b2 1147This method takes a type constraint name and returns the normalized
1148form. This removes any whitespace in the string.
004222dc 1149
e7fcb7b2 1150=item B<create_type_constraint_union($pipe_separated_types | @type_constraint_names)>
004222dc 1151
e7fcb7b2 1152This can take a union type specification like C<'Int|ArrayRef[Int]'>,
1153or a list of names. It returns a new
1154L<Moose::Meta::TypeConstraint::Union> object.
004222dc 1155
e7fcb7b2 1156=item B<create_parameterized_type_constraint($type_name)>
620db045 1157
e7fcb7b2 1158Given a C<$type_name> in the form of C<'BaseType[ContainerType]'>,
1159this will create a new L<Moose::Meta::TypeConstraint::Parameterized>
1160object. The C<BaseType> must exist already exist as a parameterizable
1161type.
620db045 1162
e7fcb7b2 1163=item B<create_class_type_constraint($class, $options)>
dabed765 1164
e7fcb7b2 1165Given a class name this function will create a new
1166L<Moose::Meta::TypeConstraint::Class> object for that class name.
004222dc 1167
e7fcb7b2 1168The C<$options> is a hash reference that will be passed to the
1169L<Moose::Meta::TypeConstraint::Class> constructor (as a hash).
620db045 1170
e7fcb7b2 1171=item B<create_role_type_constraint($role, $options)>
620db045 1172
e7fcb7b2 1173Given a role name this function will create a new
1174L<Moose::Meta::TypeConstraint::Role> object for that role name.
620db045 1175
e7fcb7b2 1176The C<$options> is a hash reference that will be passed to the
1177L<Moose::Meta::TypeConstraint::Role> constructor (as a hash).
620db045 1178
8a6c8c47 1179=item B<create_enum_type_constraint($name, $values)>
1180
1181Given a enum name this function will create a new
1182L<Moose::Meta::TypeConstraint::Enum> object for that enum name.
1183
e7fcb7b2 1184=item B<find_or_parse_type_constraint($type_name)>
620db045 1185
ec4b72d2 1186Given a type name, this first attempts to find a matching constraint
e7fcb7b2 1187in the global registry.
620db045 1188
e7fcb7b2 1189If the type name is a union or parameterized type, it will create a
1190new object of the appropriate, but if given a "regular" type that does
1191not yet exist, it simply returns false.
620db045 1192
e7fcb7b2 1193When given a union or parameterized type, the member or base type must
1194already exist.
620db045 1195
e7fcb7b2 1196If it creates a new union or parameterized type, it will add it to the
1197global registry.
004222dc 1198
e7fcb7b2 1199=item B<find_or_create_isa_type_constraint($type_name)>
004222dc 1200
e7fcb7b2 1201=item B<find_or_create_does_type_constraint($type_name)>
004222dc 1202
e7fcb7b2 1203These functions will first call C<find_or_parse_type_constraint>. If
1204that function does not return a type, a new anonymous type object will
1205be created.
004222dc 1206
e7fcb7b2 1207The C<isa> variant will use C<create_class_type_constraint> and the
1208C<does> variant will use C<create_role_type_constraint>.
004222dc 1209
1210=item B<get_type_constraint_registry>
1211
e7fcb7b2 1212Returns the L<Moose::Meta::TypeConstraint::Registry> object which
004222dc 1213keeps track of all type constraints.
1214
1215=item B<list_all_type_constraints>
1216
e7fcb7b2 1217This will return a list of type constraint names in the global
1218registry. You can then fetch the actual type object using
1219C<find_type_constraint($type_name)>.
004222dc 1220
1221=item B<list_all_builtin_type_constraints>
1222
e7fcb7b2 1223This will return a list of builtin type constraints, meaning those
1224which are defined in this module. See the L<Default Type Constraints>
1225section for a complete list.
004222dc 1226
1227=item B<export_type_constraints_as_functions>
1228
e7fcb7b2 1229This will export all the current type constraints as functions into
1230the caller's namespace (C<Int()>, C<Str()>, etc). Right now, this is
1231mostly used for testing, but it might prove useful to others.
004222dc 1232
1233=item B<get_all_parameterizable_types>
1234
e7fcb7b2 1235This returns all the parameterizable types that have been registered,
1236as a list of type objects.
004222dc 1237
e7fcb7b2 1238=item B<add_parameterizable_type($type)>
004222dc 1239
1240Adds C<$type> to the list of parameterizable types
1241
1242=back
1243
a15dff8d 1244=head1 BUGS
1245
e85d2a5d 1246All complex software has bugs lurking in it, and this module is no
a15dff8d 1247exception. If you find a bug please either email me, or add the bug
1248to cpan-RT.
1249
a15dff8d 1250=head1 AUTHOR
1251
1252Stevan Little E<lt>stevan@iinteractive.comE<gt>
1253
1254=head1 COPYRIGHT AND LICENSE
1255
2840a3b2 1256Copyright 2006-2009 by Infinity Interactive, Inc.
a15dff8d 1257
1258L<http://www.iinteractive.com>
1259
1260This library is free software; you can redistribute it and/or modify
e85d2a5d 1261it under the same terms as Perl itself.
a15dff8d 1262
81dc201f 1263=cut