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