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