specify prototyping behavior in Moose.xs
[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 =>
278 'Calling type() with a simple list of parameters is deprecated'
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 =>
303 'Calling subtype() with a simple list of parameters is deprecated'
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 =>
316 'Calling subtype() with a simple list of parameters is deprecated'
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 =>
327 'Calling subtype() with a simple list of parameters is deprecated'
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#
417# If as() returns all it's extra arguments, this just works, and
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;
730subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } =>
731 optimize_as
732 \&Moose::Util::TypeConstraints::OptimizedConstraints::RegexpRef;
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
e85d2a5d 744# NOTE:
a15dff8d 745# blessed(qr/.../) returns true,.. how odd
180899ed 746subtype 'Object' => as 'Ref' =>
747 where { blessed($_) && blessed($_) ne 'Regexp' } =>
748 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Object;
a15dff8d 749
4831e2de 750# This type is deprecated.
180899ed 751subtype 'Role' => as 'Object' => where { $_->can('does') } =>
752 optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Role;
e85d2a5d 753
180899ed 754my $_class_name_checker = sub { };
0e0709ea 755
180899ed 756subtype 'ClassName' => as 'Str' =>
757 where { Class::MOP::is_class_loaded($_) } => optimize_as
758 \&Moose::Util::TypeConstraints::OptimizedConstraints::ClassName;
02a0fb52 759
180899ed 760subtype 'RoleName' => as 'ClassName' => where {
6b885dfa 761 (Class::MOP::class_of($_) || return)->isa('Moose::Meta::Role');
180899ed 762} => optimize_as
763 \&Moose::Util::TypeConstraints::OptimizedConstraints::RoleName;
f0cac16f 764
d9b40005 765## --------------------------------------------------------
7e4e1ad4 766# parameterizable types ...
767
768$REGISTRY->add_type_constraint(
769 Moose::Meta::TypeConstraint::Parameterizable->new(
2c29c0e7 770 name => 'ScalarRef',
771 package_defined_in => __PACKAGE__,
772 parent => find_type_constraint('Ref'),
150e5142 773 constraint => sub { ref($_) eq 'SCALAR' || ref($_) eq 'REF' },
2c29c0e7 774 optimized =>
775 \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef,
776 constraint_generator => sub {
777 my $type_parameter = shift;
778 my $check = $type_parameter->_compiled_type_constraint;
779 return sub {
780 return $check->(${ $_ });
781 };
782 }
783 )
784);
785
786$REGISTRY->add_type_constraint(
787 Moose::Meta::TypeConstraint::Parameterizable->new(
180899ed 788 name => 'ArrayRef',
789 package_defined_in => __PACKAGE__,
790 parent => find_type_constraint('Ref'),
791 constraint => sub { ref($_) eq 'ARRAY' },
792 optimized =>
793 \&Moose::Util::TypeConstraints::OptimizedConstraints::ArrayRef,
7e4e1ad4 794 constraint_generator => sub {
795 my $type_parameter = shift;
180899ed 796 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 797 return sub {
798 foreach my $x (@$_) {
180899ed 799 ( $check->($x) ) || return;
800 }
801 1;
802 }
7e4e1ad4 803 }
804 )
805);
806
807$REGISTRY->add_type_constraint(
808 Moose::Meta::TypeConstraint::Parameterizable->new(
180899ed 809 name => 'HashRef',
810 package_defined_in => __PACKAGE__,
811 parent => find_type_constraint('Ref'),
812 constraint => sub { ref($_) eq 'HASH' },
813 optimized =>
814 \&Moose::Util::TypeConstraints::OptimizedConstraints::HashRef,
7e4e1ad4 815 constraint_generator => sub {
4ab662d6 816 my $type_parameter = shift;
180899ed 817 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 818 return sub {
180899ed 819 foreach my $x ( values %$_ ) {
820 ( $check->($x) ) || return;
821 }
822 1;
823 }
7e4e1ad4 824 }
825 )
826);
827
828$REGISTRY->add_type_constraint(
829 Moose::Meta::TypeConstraint::Parameterizable->new(
830 name => 'Maybe',
831 package_defined_in => __PACKAGE__,
832 parent => find_type_constraint('Item'),
180899ed 833 constraint => sub {1},
7e4e1ad4 834 constraint_generator => sub {
4ab662d6 835 my $type_parameter = shift;
180899ed 836 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 837 return sub {
180899ed 838 return 1 if not( defined($_) ) || $check->($_);
7e4e1ad4 839 return;
180899ed 840 }
7e4e1ad4 841 }
842 )
843);
844
180899ed 845my @PARAMETERIZABLE_TYPES
2c29c0e7 846 = map { $REGISTRY->get_type_constraint($_) } qw[ScalarRef ArrayRef HashRef Maybe];
180899ed 847
848sub get_all_parameterizable_types {@PARAMETERIZABLE_TYPES}
7e4e1ad4 849
4ab662d6 850sub add_parameterizable_type {
7e4e1ad4 851 my $type = shift;
180899ed 852 ( blessed $type
853 && $type->isa('Moose::Meta::TypeConstraint::Parameterizable') )
854 || __PACKAGE__->_throw_error(
855 "Type must be a Moose::Meta::TypeConstraint::Parameterizable not $type"
856 );
7e4e1ad4 857 push @PARAMETERIZABLE_TYPES => $type;
4ab662d6 858}
7e4e1ad4 859
860## --------------------------------------------------------
d9b40005 861# end of built-in types ...
862## --------------------------------------------------------
863
943596a6 864{
865 my @BUILTINS = list_all_type_constraints();
180899ed 866 sub list_all_builtin_type_constraints {@BUILTINS}
943596a6 867}
868
6ea98933 869sub _throw_error {
6b83828f 870 shift;
6ea98933 871 require Moose;
872 unshift @_, 'Moose';
873 goto &Moose::throw_error;
874}
875
a15dff8d 8761;
877
ad46f524 878# ABSTRACT: Type constraint system for Moose
879
a15dff8d 880__END__
881
882=pod
883
a15dff8d 884=head1 SYNOPSIS
885
886 use Moose::Util::TypeConstraints;
887
e85d2a5d 888 subtype 'Natural'
e606ae5f 889 => as 'Int'
a15dff8d 890 => where { $_ > 0 };
e85d2a5d 891
892 subtype 'NaturalLessThanTen'
2c0cbef7 893 => as 'Natural'
79592a54 894 => where { $_ < 10 }
895 => message { "This number ($_) is not less than ten!" };
e85d2a5d 896
897 coerce 'Num'
2c0cbef7 898 => from 'Str'
e85d2a5d 899 => via { 0+$_ };
900
2c0cbef7 901 enum 'RGBColors' => qw(red green blue);
a15dff8d 902
e7fcb7b2 903 no Moose::Util::TypeConstraints;
904
a15dff8d 905=head1 DESCRIPTION
906
e85d2a5d 907This module provides Moose with the ability to create custom type
6549b0d1 908constraints to be used in attribute definition.
e522431d 909
6ba6d68c 910=head2 Important Caveat
911
e85d2a5d 912This is B<NOT> a type system for Perl 5. These are type constraints,
913and they are not used by Moose unless you tell it to. No type
e7fcb7b2 914inference is performed, expressions are not typed, etc. etc. etc.
6ba6d68c 915
e7fcb7b2 916A type constraint is at heart a small "check if a value is valid"
917function. A constraint can be associated with an attribute. This
918simplifies parameter validation, and makes your code clearer to read,
919because you can refer to constraints by name.
6ba6d68c 920
2c0cbef7 921=head2 Slightly Less Important Caveat
922
e7fcb7b2 923It is B<always> a good idea to quote your type names.
004222dc 924
e7fcb7b2 925This prevents Perl from trying to execute the call as an indirect
926object call. This can be an issue when you have a subtype with the
927same name as a valid class.
2c0cbef7 928
e7fcb7b2 929For instance:
e85d2a5d 930
2c0cbef7 931 subtype DateTime => as Object => where { $_->isa('DateTime') };
932
e7fcb7b2 933will I<just work>, while this:
2c0cbef7 934
935 use DateTime;
936 subtype DateTime => as Object => where { $_->isa('DateTime') };
937
e85d2a5d 938will fail silently and cause many headaches. The simple way to solve
939this, as well as future proof your subtypes from classes which have
e7fcb7b2 940yet to have been created, is to quote the type name:
2c0cbef7 941
942 use DateTime;
d44714be 943 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 944
6ba6d68c 945=head2 Default Type Constraints
e522431d 946
e606ae5f 947This module also provides a simple hierarchy for Perl 5 types, here is
004222dc 948that hierarchy represented visually.
e522431d 949
950 Any
e85d2a5d 951 Item
5a4c5493 952 Bool
7e4e1ad4 953 Maybe[`a]
f65cb534 954 Undef
955 Defined
5a4c5493 956 Value
5a4c5493 957 Str
f1bbe1e1 958 Num
959 Int
fcb5b0cd 960 ClassName
961 RoleName
5a4c5493 962 Ref
2c29c0e7 963 ScalarRef[`a]
7e4e1ad4 964 ArrayRef[`a]
965 HashRef[`a]
5a4c5493 966 CodeRef
967 RegexpRef
3f7376b0 968 GlobRef
fcb5b0cd 969 FileHandle
e85d2a5d 970 Object
e522431d 971
4ab662d6 972B<NOTE:> Any type followed by a type parameter C<[`a]> can be
7e4e1ad4 973parameterized, this means you can say:
974
757e07ef 975 ArrayRef[Int] # an array of integers
7e4e1ad4 976 HashRef[CodeRef] # a hash of str to CODE ref mappings
2c29c0e7 977 ScalarRef[Int] # a reference to an integer
7e4e1ad4 978 Maybe[Str] # value may be a string, may be undefined
979
4e8a0f64 980If Moose finds a name in brackets that it does not recognize as an
981existing type, it assumes that this is a class name, for example
982C<ArrayRef[DateTime]>.
983
e7fcb7b2 984B<NOTE:> Unless you parameterize a type, then it is invalid to include
985the square brackets. I.e. C<ArrayRef[]> will be treated as a new type
986name, I<not> as a parameterization of C<ArrayRef>.
e606ae5f 987
4ab662d6 988B<NOTE:> The C<Undef> type constraint for the most part works
989correctly now, but edge cases may still exist, please use it
6549b0d1 990sparingly.
703e92fb 991
7e4e1ad4 992B<NOTE:> The C<ClassName> type constraint does a complex package
e7fcb7b2 993existence check. This means that your class B<must> be loaded for this
994type constraint to pass.
9af1d28b 995
e7fcb7b2 996B<NOTE:> The C<RoleName> constraint checks a string is a I<package
4831e2de 997name> which is a role, like C<'MyApp::Role::Comparable'>.
ed87d4fd 998
e606ae5f 999=head2 Type Constraint Naming
004222dc 1000
eee1a213 1001Type name declared via this module can only contain alphanumeric
1002characters, colons (:), and periods (.).
1003
e606ae5f 1004Since the types created by this module are global, it is suggested
1005that you namespace your types just as you would namespace your
e7fcb7b2 1006modules. So instead of creating a I<Color> type for your
1007B<My::Graphics> module, you would call the type
1008I<My::Graphics::Types::Color> instead.
004222dc 1009
703e92fb 1010=head2 Use with Other Constraint Modules
1011
e7fcb7b2 1012This module can play nicely with other constraint modules with some
1013slight tweaking. The C<where> clause in types is expected to be a
1014C<CODE> reference which checks it's first argument and returns a
1015boolean. Since most constraint modules work in a similar way, it
1016should be simple to adapt them to work with Moose.
703e92fb 1017
e85d2a5d 1018For instance, this is how you could use it with
1019L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 1020
9e856c83 1021 type 'HashOfArrayOfObjects',
1022 {
1023 where => IsHashRef(
703e92fb 1024 -keys => HasLength,
9e856c83 1025 -values => IsArrayRef(IsObject)
1026 )
1027 };
703e92fb 1028
e7fcb7b2 1029For more examples see the F<t/200_examples/004_example_w_DCS.t> test
1030file.
703e92fb 1031
e85d2a5d 1032Here is an example of using L<Test::Deep> and it's non-test
1033related C<eq_deeply> function.
703e92fb 1034
e85d2a5d 1035 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 1036 => where {
e85d2a5d 1037 eq_deeply($_,
703e92fb 1038 array_each(subhashof({
1039 bar => isa('Bar'),
1040 random_number => ignore()
e85d2a5d 1041 })))
703e92fb 1042 };
1043
e606ae5f 1044For a complete example see the
e7fcb7b2 1045F<t/200_examples/005_example_w_TestDeep.t> test file.
e85d2a5d 1046
a15dff8d 1047=head1 FUNCTIONS
1048
1049=head2 Type Constraint Constructors
1050
e7fcb7b2 1051The following functions are used to create type constraints. They
1052will also register the type constraints your create in a global
1053registry that is used to look types up by name.
a15dff8d 1054
cec39889 1055See the L</SYNOPSIS> for an example of how to use these.
a15dff8d 1056
6ba6d68c 1057=over 4
a15dff8d 1058
fbe1e4a5 1059=item B<< subtype 'Name' => as 'Parent' => where { } ... >>
182134e8 1060
e85d2a5d 1061This creates a named subtype.
d6e2d9a1 1062
dba9208a 1063If you provide a parent that Moose does not recognize, it will
1064automatically create a new class type constraint for this name.
1065
9e856c83 1066When creating a named type, the C<subtype> function should either be
1067called with the sugar helpers (C<where>, C<message>, etc), or with a
1068name and a hashref of parameters:
1069
1070 subtype( 'Foo', { where => ..., message => ... } );
1071
1072The valid hashref keys are C<as> (the parent), C<where>, C<message>,
1073and C<optimize_as>.
9a63faba 1074
fbe1e4a5 1075=item B<< subtype as 'Parent' => where { } ... >>
182134e8 1076
e85d2a5d 1077This creates an unnamed subtype and will return the type
1078constraint meta-object, which will be an instance of
1079L<Moose::Meta::TypeConstraint>.
a15dff8d 1080
9e856c83 1081When creating an anonymous type, the C<subtype> function should either
1082be called with the sugar helpers (C<where>, C<message>, etc), or with
1083just a hashref of parameters:
1084
1085 subtype( { where => ..., message => ... } );
1086
620db045 1087=item B<class_type ($class, ?$options)>
3fef8ce8 1088
ed87d4fd 1089Creates a new subtype of C<Object> with the name C<$class> and the
1090metaclass L<Moose::Meta::TypeConstraint::Class>.
3fef8ce8 1091
620db045 1092=item B<role_type ($role, ?$options)>
1093
ed87d4fd 1094Creates a C<Role> type constraint with the name C<$role> and the
1095metaclass L<Moose::Meta::TypeConstraint::Role>.
620db045 1096
1b2c9bda 1097=item B<maybe_type ($type)>
1098
1099Creates a type constraint for either C<undef> or something of the
1100given type.
1101
bce5d4a5 1102=item B<duck_type ($name, \@methods)>
e451e855 1103
88b68372 1104This will create a subtype of Object and test to make sure the value
bce5d4a5 1105C<can()> do the methods in C<\@methods>.
88b68372 1106
1107This is intended as an easy way to accept non-Moose objects that
1108provide a certain interface. If you're using Moose classes, we
1109recommend that you use a C<requires>-only Role instead.
e451e855 1110
1111=item B<duck_type (\@methods)>
1112
bce5d4a5 1113If passed an ARRAY reference as the only parameter instead of the
1114C<$name>, C<\@methods> pair, this will create an unnamed duck type.
1115This can be used in an attribute definition like so:
e451e855 1116
88b68372 1117 has 'cache' => (
1118 is => 'ro',
1119 isa => duck_type( [qw( get_set )] ),
1120 );
e451e855 1121
bce5d4a5 1122=item B<enum ($name, \@values)>
fcec2383 1123
e85d2a5d 1124This will create a basic subtype for a given set of strings.
1125The resulting constraint will be a subtype of C<Str> and
bce5d4a5 1126will match any of the items in C<\@values>. It is case sensitive.
cec39889 1127See the L</SYNOPSIS> for a simple example.
2c0cbef7 1128
6549b0d1 1129B<NOTE:> This is not a true proper enum type, it is simply
1130a convenient constraint builder.
2c0cbef7 1131
9f4334a1 1132=item B<enum (\@values)>
1133
bce5d4a5 1134If passed an ARRAY reference as the only parameter instead of the
1135C<$name>, C<\@values> pair, this will create an unnamed enum. This
1136can then be used in an attribute definition like so:
9f4334a1 1137
1138 has 'sort_order' => (
1139 is => 'ro',
4ab662d6 1140 isa => enum([qw[ ascending descending ]]),
9f4334a1 1141 );
1142
e7fcb7b2 1143=item B<as 'Parent'>
a15dff8d 1144
6ba6d68c 1145This is just sugar for the type constraint construction syntax.
a15dff8d 1146
e7fcb7b2 1147It takes a single argument, which is the name of a parent type.
1148
1149=item B<where { ... }>
a15dff8d 1150
6ba6d68c 1151This is just sugar for the type constraint construction syntax.
76d37e5a 1152
e7fcb7b2 1153It takes a subroutine reference as an argument. When the type
1154constraint is tested, the reference is run with the value to be tested
1155in C<$_>. This reference should return true or false to indicate
1156whether or not the constraint check passed.
e606ae5f 1157
e7fcb7b2 1158=item B<message { ... }>
76d37e5a 1159
1160This is just sugar for the type constraint construction syntax.
a15dff8d 1161
e7fcb7b2 1162It takes a subroutine reference as an argument. When the type
1163constraint fails, then the code block is run with the value provided
1164in C<$_>. This reference should return a string, which will be used in
1165the text of the exception thrown.
e606ae5f 1166
e7fcb7b2 1167=item B<optimize_as { ... }>
8ecb1fa0 1168
e85d2a5d 1169This can be used to define a "hand optimized" version of your
d44714be 1170type constraint which can be used to avoid traversing a subtype
6549b0d1 1171constraint hierarchy.
d44714be 1172
e85d2a5d 1173B<NOTE:> You should only use this if you know what you are doing,
1174all the built in types use this, so your subtypes (assuming they
d44714be 1175are shallow) will not likely need to use this.
1176
78d0edd7 1177=item B<< type 'Name' => where { } ... >>
e7fcb7b2 1178
1179This creates a base type, which has no parent.
1180
1181The C<type> function should either be called with the sugar helpers
1182(C<where>, C<message>, etc), or with a name and a hashref of
1183parameters:
1184
1185 type( 'Foo', { where => ..., message => ... } );
1186
1187The valid hashref keys are C<where>, C<message>, and C<optimize_as>.
1188
6ba6d68c 1189=back
a15dff8d 1190
0d29b772 1191=head2 Type Constraint Utilities
1192
1193=over 4
1194
1195=item B<< match_on_type $value => ( $type => \&action, ... ?\&default ) >>
1196
1a15f4a8 1197This is a utility function for doing simple type based dispatching similar to
2ae1457e 1198match/case in OCaml and case/of in Haskell. It is not as featureful as those
1a15f4a8 1199languages, nor does not it support any kind of automatic destructuring
1200bind. Here is a simple Perl pretty printer dispatching over the core Moose
1201types.
0d29b772 1202
1203 sub ppprint {
1204 my $x = shift;
1a15f4a8 1205 match_on_type $x => (
1206 HashRef => sub {
0d29b772 1207 my $hash = shift;
1a15f4a8 1208 '{ '
1209 . (
1210 join ", " => map { $_ . ' => ' . ppprint( $hash->{$_} ) }
1211 sort keys %$hash
1212 ) . ' }';
1213 },
1214 ArrayRef => sub {
0d29b772 1215 my $array = shift;
1a15f4a8 1216 '[ ' . ( join ", " => map { ppprint($_) } @$array ) . ' ]';
1217 },
1218 CodeRef => sub {'sub { ... }'},
1219 RegexpRef => sub { 'qr/' . $_ . '/' },
1220 GlobRef => sub { '*' . B::svref_2object($_)->NAME },
0d29b772 1221 Object => sub { $_->can('to_string') ? $_->to_string : $_ },
1a15f4a8 1222 ScalarRef => sub { '\\' . ppprint( ${$_} ) },
1223 Num => sub {$_},
1224 Str => sub { '"' . $_ . '"' },
1225 Undef => sub {'undef'},
1226 => sub { die "I don't know what $_ is" }
1227 );
0d29b772 1228 }
1229
e7597637 1230Or a simple JSON serializer:
1231
1232 sub to_json {
1233 my $x = shift;
1a15f4a8 1234 match_on_type $x => (
1235 HashRef => sub {
e7597637 1236 my $hash = shift;
1a15f4a8 1237 '{ '
1238 . (
1239 join ", " =>
1240 map { '"' . $_ . '" : ' . to_json( $hash->{$_} ) }
1241 sort keys %$hash
1242 ) . ' }';
1243 },
1244 ArrayRef => sub {
e7597637 1245 my $array = shift;
1a15f4a8 1246 '[ ' . ( join ", " => map { to_json($_) } @$array ) . ' ]';
1247 },
1248 Num => sub {$_},
1249 Str => sub { '"' . $_ . '"' },
1250 Undef => sub {'null'},
1251 => sub { die "$_ is not acceptable json type" }
1252 );
e7597637 1253 }
1254
1a15f4a8 1255The matcher is done by mapping a C<$type> to an C<\&action>. The C<$type> can
1256be either a string type or a L<Moose::Meta::TypeConstraint> object, and
1257C<\&action> is a subroutine reference. This function will dispatch on the
1258first match for C<$value>. It is possible to have a catch-all by providing an
1259additional subroutine reference as the final argument to C<match_on_type>.
0d29b772 1260
1261=back
1262
6ba6d68c 1263=head2 Type Coercion Constructors
a15dff8d 1264
e7fcb7b2 1265You can define coercions for type constraints, which allow you to
1266automatically transform values to something valid for the type
1267constraint. If you ask your accessor to coerce, then Moose will run
1268the type-coercion code first, followed by the type constraint
1269check. This feature should be used carefully as it is very powerful
1270and could easily take off a limb if you are not careful.
a15dff8d 1271
cec39889 1272See the L</SYNOPSIS> for an example of how to use these.
a15dff8d 1273
6ba6d68c 1274=over 4
a15dff8d 1275
f55dd47f 1276=item B<< coerce 'Name' => from 'OtherName' => via { ... } >>
a15dff8d 1277
e7fcb7b2 1278This defines a coercion from one type to another. The C<Name> argument
1279is the type you are coercing I<to>.
1280
f55dd47f 1281To define multiple coercions, supply more sets of from/via pairs:
1282
1283 coerce 'Name' =>
1284 from 'OtherName' => via { ... },
1285 from 'ThirdName' => via { ... };
1286
e7fcb7b2 1287=item B<from 'OtherName'>
a15dff8d 1288
6ba6d68c 1289This is just sugar for the type coercion construction syntax.
1290
e7fcb7b2 1291It takes a single type name (or type object), which is the type being
1292coerced I<from>.
1293
1294=item B<via { ... }>
a15dff8d 1295
6ba6d68c 1296This is just sugar for the type coercion construction syntax.
a15dff8d 1297
e7fcb7b2 1298It takes a subroutine reference. This reference will be called with
1299the value to be coerced in C<$_>. It is expected to return a new value
1300of the proper type for the coercion.
1301
a15dff8d 1302=back
1303
e7fcb7b2 1304=head2 Creating and Finding Type Constraints
1305
1306These are additional functions for creating and finding type
1307constraints. Most of these functions are not available for
1308importing. The ones that are importable as specified.
004222dc 1309
1310=over 4
1311
e7fcb7b2 1312=item B<find_type_constraint($type_name)>
eb4c4e82 1313
e7fcb7b2 1314This function can be used to locate the L<Moose::Meta::TypeConstraint>
1315object for a named type.
eb4c4e82 1316
e7fcb7b2 1317This function is importable.
004222dc 1318
e7fcb7b2 1319=item B<register_type_constraint($type_object)>
004222dc 1320
e7fcb7b2 1321This function will register a L<Moose::Meta::TypeConstraint> with the
1322global type registry.
004222dc 1323
e7fcb7b2 1324This function is importable.
004222dc 1325
e7fcb7b2 1326=item B<normalize_type_constraint_name($type_constraint_name)>
004222dc 1327
e7fcb7b2 1328This method takes a type constraint name and returns the normalized
1329form. This removes any whitespace in the string.
004222dc 1330
e7fcb7b2 1331=item B<create_type_constraint_union($pipe_separated_types | @type_constraint_names)>
004222dc 1332
e7fcb7b2 1333This can take a union type specification like C<'Int|ArrayRef[Int]'>,
1334or a list of names. It returns a new
1335L<Moose::Meta::TypeConstraint::Union> object.
004222dc 1336
e7fcb7b2 1337=item B<create_parameterized_type_constraint($type_name)>
620db045 1338
e7fcb7b2 1339Given a C<$type_name> in the form of C<'BaseType[ContainerType]'>,
1340this will create a new L<Moose::Meta::TypeConstraint::Parameterized>
1341object. The C<BaseType> must exist already exist as a parameterizable
1342type.
620db045 1343
e7fcb7b2 1344=item B<create_class_type_constraint($class, $options)>
dabed765 1345
e7fcb7b2 1346Given a class name this function will create a new
1347L<Moose::Meta::TypeConstraint::Class> object for that class name.
004222dc 1348
e7fcb7b2 1349The C<$options> is a hash reference that will be passed to the
1350L<Moose::Meta::TypeConstraint::Class> constructor (as a hash).
620db045 1351
e7fcb7b2 1352=item B<create_role_type_constraint($role, $options)>
620db045 1353
e7fcb7b2 1354Given a role name this function will create a new
1355L<Moose::Meta::TypeConstraint::Role> object for that role name.
620db045 1356
e7fcb7b2 1357The C<$options> is a hash reference that will be passed to the
1358L<Moose::Meta::TypeConstraint::Role> constructor (as a hash).
620db045 1359
8a6c8c47 1360=item B<create_enum_type_constraint($name, $values)>
1361
1362Given a enum name this function will create a new
1363L<Moose::Meta::TypeConstraint::Enum> object for that enum name.
1364
0a6bff54 1365=item B<create_duck_type_constraint($name, $methods)>
1366
1367Given a duck type name this function will create a new
1368L<Moose::Meta::TypeConstraint::DuckType> object for that enum name.
1369
e7fcb7b2 1370=item B<find_or_parse_type_constraint($type_name)>
620db045 1371
ec4b72d2 1372Given a type name, this first attempts to find a matching constraint
e7fcb7b2 1373in the global registry.
620db045 1374
e7fcb7b2 1375If the type name is a union or parameterized type, it will create a
1376new object of the appropriate, but if given a "regular" type that does
1377not yet exist, it simply returns false.
620db045 1378
e7fcb7b2 1379When given a union or parameterized type, the member or base type must
1380already exist.
620db045 1381
e7fcb7b2 1382If it creates a new union or parameterized type, it will add it to the
1383global registry.
004222dc 1384
e7fcb7b2 1385=item B<find_or_create_isa_type_constraint($type_name)>
004222dc 1386
e7fcb7b2 1387=item B<find_or_create_does_type_constraint($type_name)>
004222dc 1388
e7fcb7b2 1389These functions will first call C<find_or_parse_type_constraint>. If
1390that function does not return a type, a new anonymous type object will
1391be created.
004222dc 1392
e7fcb7b2 1393The C<isa> variant will use C<create_class_type_constraint> and the
1394C<does> variant will use C<create_role_type_constraint>.
004222dc 1395
1396=item B<get_type_constraint_registry>
1397
e7fcb7b2 1398Returns the L<Moose::Meta::TypeConstraint::Registry> object which
004222dc 1399keeps track of all type constraints.
1400
1401=item B<list_all_type_constraints>
1402
e7fcb7b2 1403This will return a list of type constraint names in the global
1404registry. You can then fetch the actual type object using
1405C<find_type_constraint($type_name)>.
004222dc 1406
1407=item B<list_all_builtin_type_constraints>
1408
e7fcb7b2 1409This will return a list of builtin type constraints, meaning those
1410which are defined in this module. See the L<Default Type Constraints>
1411section for a complete list.
004222dc 1412
1413=item B<export_type_constraints_as_functions>
1414
e7fcb7b2 1415This will export all the current type constraints as functions into
1416the caller's namespace (C<Int()>, C<Str()>, etc). Right now, this is
1417mostly used for testing, but it might prove useful to others.
004222dc 1418
1419=item B<get_all_parameterizable_types>
1420
e7fcb7b2 1421This returns all the parameterizable types that have been registered,
1422as a list of type objects.
004222dc 1423
e7fcb7b2 1424=item B<add_parameterizable_type($type)>
004222dc 1425
1426Adds C<$type> to the list of parameterizable types
1427
1428=back
1429
a15dff8d 1430=head1 BUGS
1431
d4048ef3 1432See L<Moose/BUGS> for details on reporting bugs.
a15dff8d 1433
81dc201f 1434=cut