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