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