I'm going to take away jnapiorkowski's tab key!
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints.pm
CommitLineData
a15dff8d 1
2package Moose::Util::TypeConstraints;
3
4use strict;
5use warnings;
6
998a8a25 7use Carp ();
21f1e231 8use Scalar::Util 'blessed';
e606ae5f 9use Moose::Exporter;
a15dff8d 10
e606ae5f 11our $VERSION = '0.57';
12$VERSION = eval $VERSION;
d44714be 13our $AUTHORITY = 'cpan:STEVAN';
a15dff8d 14
d9b40005 15## --------------------------------------------------------
e85d2a5d 16# Prototyped subs must be predeclared because we have a
17# circular dependency with Moose::Meta::Attribute et. al.
18# so in case of us being use'd first the predeclaration
d9b40005 19# ensures the prototypes are in scope when consumers are
20# compiled.
21
22# creation and location
0fbd4b0a 23sub find_type_constraint ($);
3fef8ce8 24sub register_type_constraint ($);
0fbd4b0a 25sub find_or_create_type_constraint ($;$);
620db045 26sub find_or_parse_type_constraint ($);
27sub find_or_create_isa_type_constraint ($);
28sub find_or_create_does_type_constraint ($);
0fbd4b0a 29sub create_type_constraint_union (@);
30sub create_parameterized_type_constraint ($);
4ab662d6 31sub create_class_type_constraint ($;$);
620db045 32sub create_role_type_constraint ($;$);
dabed765 33sub create_enum_type_constraint ($$);
d9b40005 34
35# dah sugah!
36sub type ($$;$$);
37sub subtype ($$;$$$);
4ab662d6 38sub class_type ($;$);
d9b40005 39sub coerce ($@);
40sub as ($);
41sub from ($);
42sub where (&);
43sub via (&);
44sub message (&);
45sub optimize_as (&);
46sub enum ($;@);
47
e85d2a5d 48## private stuff ...
d9b40005 49sub _create_type_constraint ($$$;$$);
50sub _install_type_coercions ($$);
51
52## --------------------------------------------------------
8c4acc60 53
4e036ee4 54use Moose::Meta::TypeConstraint;
3726f905 55use Moose::Meta::TypeConstraint::Union;
0fbd4b0a 56use Moose::Meta::TypeConstraint::Parameterized;
7e4e1ad4 57use Moose::Meta::TypeConstraint::Parameterizable;
620db045 58use Moose::Meta::TypeConstraint::Class;
59use Moose::Meta::TypeConstraint::Role;
dabed765 60use Moose::Meta::TypeConstraint::Enum;
2ca63f5d 61use Moose::Meta::TypeCoercion;
3726f905 62use Moose::Meta::TypeCoercion::Union;
22aed3c0 63use Moose::Meta::TypeConstraint::Registry;
28ffb449 64use Moose::Util::TypeConstraints::OptimizedConstraints;
4e036ee4 65
e606ae5f 66Moose::Exporter->setup_import_methods(
67 as_is => [
68 qw(
69 type subtype class_type role_type as where message optimize_as
70 coerce from via
71 enum
72 find_type_constraint
73 register_type_constraint )
74 ],
75 _export_to_main => 1,
76);
a15dff8d 77
d9b40005 78## --------------------------------------------------------
79## type registry and some useful functions for it
80## --------------------------------------------------------
81
22aed3c0 82my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new;
587ae0d2 83
d9b40005 84sub get_type_constraint_registry { $REGISTRY }
e85d2a5d 85sub list_all_type_constraints { keys %{$REGISTRY->type_constraints} }
d9b40005 86sub export_type_constraints_as_functions {
87 my $pkg = caller();
88 no strict 'refs';
a0f8153d 89 foreach my $constraint (keys %{$REGISTRY->type_constraints}) {
42bc21a4 90 my $tc = $REGISTRY->get_type_constraint($constraint)->_compiled_type_constraint;
d2f0f6e9 91 *{"${pkg}::${constraint}"} = sub { $tc->($_[0]) ? 1 : undef }; # the undef is for compat
a0f8153d 92 }
d9b40005 93}
182134e8 94
d9b40005 95sub create_type_constraint_union (@) {
96 my @type_constraint_names;
e85d2a5d 97
f1917f58 98 if (scalar @_ == 1 && _detect_type_constraint_union($_[0])) {
99 @type_constraint_names = _parse_type_constraint_union($_[0]);
d9b40005 100 }
101 else {
102 @type_constraint_names = @_;
429ccc11 103 }
eb4c4e82 104
3726f905 105 (scalar @type_constraint_names >= 2)
c245d69b 106 || Moose->throw_error("You must pass in at least 2 type names to make a union");
e85d2a5d 107
fa92d705 108 my @type_constraints = sort {$a->name cmp $b->name} map {
08380fdb 109 find_or_parse_type_constraint($_) ||
fa92d705 110 Moose->throw_error("Could not locate type constraint ($_) for the union");
08380fdb 111 } @type_constraint_names;
112
3726f905 113 return Moose::Meta::TypeConstraint::Union->new(
fa92d705 114 type_constraints => \@type_constraints
e85d2a5d 115 );
182134e8 116}
a15dff8d 117
0fbd4b0a 118sub create_parameterized_type_constraint ($) {
d9b40005 119 my $type_constraint_name = shift;
2dd0aea3 120 my ($base_type, $type_parameter_str) = _parse_parameterized_type_constraint($type_constraint_name);
e85d2a5d 121
2dd0aea3 122 (defined $base_type && defined $type_parameter_str)
c245d69b 123 || Moose->throw_error("Could not parse type name ($type_constraint_name) correctly");
e85d2a5d 124
2dd0aea3 125 if ($REGISTRY->has_type_constraint($base_type)) {
126 my $base_type_tc = $REGISTRY->get_type_constraint($base_type);
127 return _create_parameterized_type_constraint(
2dd0aea3 128 $base_type_tc,
129 $type_parameter_str,
130 );
131 } else {
132 Moose->throw_error("Could not locate the base type ($base_type)");
133 }
134}
e85d2a5d 135
2dd0aea3 136sub _create_parameterized_type_constraint {
73e37d3b 137 my ( $base_type_tc, $type_parameter_str ) = @_;
138 if ( $base_type_tc->can('parameterize') ) {
139 my @type_parameters_tc
140 = $base_type_tc->parse_parameter_str($type_parameter_str);
141 return $base_type_tc->parameterize(@type_parameters_tc);
142 }
143 else {
2dd0aea3 144 return Moose::Meta::TypeConstraint::Parameterized->new(
73e37d3b 145 name => $base_type_tc->name . '[' . $type_parameter_str . ']',
146 parent => $base_type_tc,
147 type_parameter =>
148 find_or_create_isa_type_constraint($type_parameter_str),
2dd0aea3 149 );
73e37d3b 150 }
22aed3c0 151}
152
4ab662d6 153#should we also support optimized checks?
154sub create_class_type_constraint ($;$) {
620db045 155 my ( $class, $options ) = @_;
156
3fef8ce8 157 # too early for this check
158 #find_type_constraint("ClassName")->check($class)
c245d69b 159 # || Moose->throw_error("Can't create a class type constraint because '$class' is not a class name");
3fef8ce8 160
620db045 161 my %options = (
162 class => $class,
163 name => $class,
164 %{ $options || {} },
4ab662d6 165 );
620db045 166
167 $options{name} ||= "__ANON__";
168
169 Moose::Meta::TypeConstraint::Class->new( %options );
3fef8ce8 170}
171
620db045 172sub create_role_type_constraint ($;$) {
173 my ( $role, $options ) = @_;
e85d2a5d 174
620db045 175 # too early for this check
176 #find_type_constraint("ClassName")->check($class)
c245d69b 177 # || Moose->throw_error("Can't create a class type constraint because '$class' is not a class name");
e85d2a5d 178
620db045 179 my %options = (
180 role => $role,
181 name => $role,
182 %{ $options || {} },
183 );
e85d2a5d 184
620db045 185 $options{name} ||= "__ANON__";
186
187 Moose::Meta::TypeConstraint::Role->new( %options );
188}
189
190
191sub find_or_create_type_constraint ($;$) {
192 my ( $type_constraint_name, $options_for_anon_type ) = @_;
193
194 if ( my $constraint = find_or_parse_type_constraint($type_constraint_name) ) {
195 return $constraint;
d9b40005 196 }
620db045 197 elsif ( defined $options_for_anon_type ) {
d9b40005 198 # NOTE:
4ab662d6 199 # if there is no $options_for_anon_type
200 # specified, then we assume they don't
f3c4e20e 201 # want to create one, and return nothing.
f3c4e20e 202
d9b40005 203 # otherwise assume that we should create
e85d2a5d 204 # an ANON type with the $options_for_anon_type
d9b40005 205 # options which can be passed in. It should
e85d2a5d 206 # be noted that these don't get registered
d9b40005 207 # so we need to return it.
208 # - SL
209 return Moose::Meta::TypeConstraint->new(
210 name => '__ANON__',
e85d2a5d 211 %{$options_for_anon_type}
d9b40005 212 );
213 }
e85d2a5d 214
620db045 215 return;
216}
217
218sub find_or_create_isa_type_constraint ($) {
219 my $type_constraint_name = shift;
5e2ada84 220 find_or_parse_type_constraint($type_constraint_name) || create_class_type_constraint($type_constraint_name)
620db045 221}
222
223sub find_or_create_does_type_constraint ($) {
224 my $type_constraint_name = shift;
5e2ada84 225 find_or_parse_type_constraint($type_constraint_name) || create_role_type_constraint($type_constraint_name)
620db045 226}
227
228sub find_or_parse_type_constraint ($) {
eb4c4e82 229 my $type_constraint_name = normalize_type_constraint_name(shift);
620db045 230 my $constraint;
e606ae5f 231
232 if ($constraint = find_type_constraint($type_constraint_name)) {
233 return $constraint;
234 } elsif (_detect_type_constraint_union($type_constraint_name)) {
620db045 235 $constraint = create_type_constraint_union($type_constraint_name);
08380fdb 236 } elsif (_detect_parameterized_type_constraint($type_constraint_name)) {
620db045 237 $constraint = create_parameterized_type_constraint($type_constraint_name);
238 } else {
239 return;
240 }
bb6c8335 241
d9b40005 242 $REGISTRY->add_type_constraint($constraint);
e85d2a5d 243 return $constraint;
d9b40005 244}
22aed3c0 245
eb4c4e82 246sub normalize_type_constraint_name {
247 my $type_constraint_name = shift @_;
248 $type_constraint_name =~s/\s//g;
249 return $type_constraint_name;
250}
251
22aed3c0 252## --------------------------------------------------------
253## exported functions ...
254## --------------------------------------------------------
255
eeedfc8a 256sub find_type_constraint ($) {
257 my $type = shift;
258
259 if ( blessed $type and $type->isa("Moose::Meta::TypeConstraint") ) {
260 return $type;
e606ae5f 261 }
262 else {
263 return unless $REGISTRY->has_type_constraint($type);
eeedfc8a 264 return $REGISTRY->get_type_constraint($type);
265 }
266}
22aed3c0 267
3fef8ce8 268sub register_type_constraint ($) {
269 my $constraint = shift;
c245d69b 270 Moose->throw_error("can't register an unnamed type constraint") unless defined $constraint->name;
3fef8ce8 271 $REGISTRY->add_type_constraint($constraint);
dabed765 272 return $constraint;
3fef8ce8 273}
274
7c13858b 275# type constructors
a15dff8d 276
815ec671 277sub type ($$;$$) {
1b7df21f 278 splice(@_, 1, 0, undef);
a0f8153d 279 goto &_create_type_constraint;
a15dff8d 280}
281
8ecb1fa0 282sub subtype ($$;$$$) {
86629f93 283 # NOTE:
284 # this adds an undef for the name
285 # if this is an anon-subtype:
286 # subtype(Num => where { $_ % 2 == 0 }) # anon 'even' subtype
287 # but if the last arg is not a code
288 # ref then it is a subtype alias:
289 # subtype(MyNumbers => as Num); # now MyNumbers is the same as Num
e85d2a5d 290 # ... yeah I know it's ugly code
86629f93 291 # - SL
21f1e231 292 unshift @_ => undef if scalar @_ <= 2 && ('CODE' eq ref($_[1]));
a0f8153d 293 goto &_create_type_constraint;
a15dff8d 294}
295
4ab662d6 296sub class_type ($;$) {
297 register_type_constraint(
298 create_class_type_constraint(
299 $_[0],
300 ( defined($_[1]) ? $_[1] : () ),
301 )
302 );
3fef8ce8 303}
304
620db045 305sub role_type ($;$) {
306 register_type_constraint(
307 create_role_type_constraint(
308 $_[0],
309 ( defined($_[1]) ? $_[1] : () ),
310 )
311 );
312}
313
4b598ea3 314sub coerce ($@) {
e85d2a5d 315 my ($type_name, @coercion_map) = @_;
7c13858b 316 _install_type_coercions($type_name, \@coercion_map);
182134e8 317}
318
76d37e5a 319sub as ($) { $_[0] }
320sub from ($) { $_[0] }
321sub where (&) { $_[0] }
322sub via (&) { $_[0] }
8ecb1fa0 323
324sub message (&) { +{ message => $_[0] } }
325sub optimize_as (&) { +{ optimized => $_[0] } }
a15dff8d 326
2c0cbef7 327sub enum ($;@) {
fcec2383 328 my ($type_name, @values) = @_;
4ab662d6 329 # NOTE:
330 # if only an array-ref is passed then
9f4334a1 331 # you get an anon-enum
332 # - SL
333 if (ref $type_name eq 'ARRAY' && !@values) {
334 @values = @$type_name;
335 $type_name = undef;
336 }
2c0cbef7 337 (scalar @values >= 2)
c245d69b 338 || Moose->throw_error("You must have at least two values to enumerate through");
c4fe165f 339 my %valid = map { $_ => 1 } @values;
dabed765 340
341 register_type_constraint(
342 create_enum_type_constraint(
343 $type_name,
344 \@values,
345 )
346 );
347}
348
349sub create_enum_type_constraint ($$) {
350 my ( $type_name, $values ) = @_;
e606ae5f 351
dabed765 352 Moose::Meta::TypeConstraint::Enum->new(
353 name => $type_name || '__ANON__',
354 values => $values,
a0f8153d 355 );
fcec2383 356}
357
d9b40005 358## --------------------------------------------------------
359## desugaring functions ...
360## --------------------------------------------------------
361
e85d2a5d 362sub _create_type_constraint ($$$;$$) {
d9b40005 363 my $name = shift;
364 my $parent = shift;
8de73ff1 365 my $check = shift;
e85d2a5d 366
d9b40005 367 my ($message, $optimized);
368 for (@_) {
369 $message = $_->{message} if exists $_->{message};
e85d2a5d 370 $optimized = $_->{optimized} if exists $_->{optimized};
d9b40005 371 }
372
373 my $pkg_defined_in = scalar(caller(0));
e85d2a5d 374
d9b40005 375 if (defined $name) {
376 my $type = $REGISTRY->get_type_constraint($name);
e85d2a5d 377
d9b40005 378 ($type->_package_defined_in eq $pkg_defined_in)
e85d2a5d 379 || confess ("The type constraint '$name' has already been created in "
d9b40005 380 . $type->_package_defined_in . " and cannot be created again in "
381 . $pkg_defined_in)
e85d2a5d 382 if defined $type;
383 }
384
36dbd105 385 my $class = "Moose::Meta::TypeConstraint";
4ab662d6 386
36dbd105 387 # FIXME should probably not be a special case
36dbd105 388 if ( defined $parent and $parent = find_or_parse_type_constraint($parent) ) {
e606ae5f 389 $class = "Moose::Meta::TypeConstraint::Parameterizable"
a84a89ba 390 if $parent->isa("Moose::Meta::TypeConstraint::Parameterizable");
36dbd105 391 }
392
393 my $constraint = $class->new(
d9b40005 394 name => $name || '__ANON__',
d9b40005 395 package_defined_in => $pkg_defined_in,
e85d2a5d 396
397 ($parent ? (parent => $parent ) : ()),
398 ($check ? (constraint => $check) : ()),
399 ($message ? (message => $message) : ()),
400 ($optimized ? (optimized => $optimized) : ()),
d9b40005 401 );
4ab662d6 402
8de73ff1 403 # NOTE:
4ab662d6 404 # if we have a type constraint union, and no
8de73ff1 405 # type check, this means we are just aliasing
4ab662d6 406 # the union constraint, which means we need to
8de73ff1 407 # handle this differently.
408 # - SL
4ab662d6 409 if (not(defined $check)
410 && $parent->isa('Moose::Meta::TypeConstraint::Union')
411 && $parent->has_coercion
8de73ff1 412 ){
413 $constraint->coercion(Moose::Meta::TypeCoercion::Union->new(
414 type_constraint => $parent
415 ));
4ab662d6 416 }
d9b40005 417
418 $REGISTRY->add_type_constraint($constraint)
419 if defined $name;
420
421 return $constraint;
422}
423
e85d2a5d 424sub _install_type_coercions ($$) {
d9b40005 425 my ($type_name, $coercion_map) = @_;
e606ae5f 426 my $type = find_type_constraint($type_name);
6f9ff1af 427 (defined $type)
c245d69b 428 || Moose->throw_error("Cannot find type '$type_name', perhaps you forgot to load it.");
41e007e4 429 if ($type->has_coercion) {
430 $type->coercion->add_type_coercions(@$coercion_map);
431 }
432 else {
433 my $type_coercion = Moose::Meta::TypeCoercion->new(
434 type_coercion_map => $coercion_map,
435 type_constraint => $type
436 );
437 $type->coercion($type_coercion);
438 }
d9b40005 439}
440
441## --------------------------------------------------------
f1917f58 442## type notation parsing ...
443## --------------------------------------------------------
444
445{
e85d2a5d 446 # All I have to say is mugwump++ cause I know
447 # do not even have enough regexp-fu to be able
448 # to have written this (I can only barely
f1917f58 449 # understand it as it is)
e85d2a5d 450 # - SL
451
f1917f58 452 use re "eval";
453
3796382a 454 my $valid_chars = qr{[\w:]};
f1917f58 455 my $type_atom = qr{ $valid_chars+ };
456
be722745 457 my $any;
458
08380fdb 459 my $type = qr{ $valid_chars+ (?: \[ \s* (??{$any}) \s* \] )? }x;
460 my $type_capture_parts = qr{ ($valid_chars+) (?: \[ \s* ((??{$any})) \s* \] )? }x;
461 my $type_with_parameter = qr{ $valid_chars+ \[ \s* (??{$any}) \s* \] }x;
f1917f58 462
3796382a 463 my $op_union = qr{ \s* \| \s* }x;
f1917f58 464 my $union = qr{ $type (?: $op_union $type )+ }x;
465
08380fdb 466 ## New Stuff for structured types.
467 my $comma = qr{,};
468 my $indirection = qr{=>};
469 my $divider_ops = qr{ $comma | $indirection }x;
470 my $structure_divider = qr{\s* $divider_ops \s*}x;
471 my $structure_elements = qr{ ($type $structure_divider*)+ }x;
472
473 $any = qr{ $type | $union | $structure_elements }x;
f1917f58 474
0fbd4b0a 475 sub _parse_parameterized_type_constraint {
be722745 476 { no warnings 'void'; $any; } # force capture of interpolated lexical
08380fdb 477 my($base, $elements) = ($_[0] =~ m{ $type_capture_parts }x);
a4becd2b 478 return ($base,$elements);
f1917f58 479 }
480
0fbd4b0a 481 sub _detect_parameterized_type_constraint {
be722745 482 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 483 $_[0] =~ m{ ^ $type_with_parameter $ }x;
f1917f58 484 }
485
486 sub _parse_type_constraint_union {
be722745 487 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 488 my $given = shift;
489 my @rv;
490 while ( $given =~ m{ \G (?: $op_union )? ($type) }gcx ) {
82a5b1a7 491 push @rv => $1;
e85d2a5d 492 }
493 (pos($given) eq length($given))
c245d69b 494 || Moose->throw_error("'$given' didn't parse (parse-pos="
e85d2a5d 495 . pos($given)
496 . " and str-length="
497 . length($given)
4c0b3599 498 . ")");
e85d2a5d 499 @rv;
f1917f58 500 }
501
502 sub _detect_type_constraint_union {
be722745 503 { no warnings 'void'; $any; } # force capture of interpolated lexical
e85d2a5d 504 $_[0] =~ m{^ $type $op_union $type ( $op_union .* )? $}x;
f1917f58 505 }
506}
507
508## --------------------------------------------------------
d9b40005 509# define some basic built-in types
510## --------------------------------------------------------
a15dff8d 511
f65cb534 512type 'Any' => where { 1 }; # meta-type including all
e85d2a5d 513type 'Item' => where { 1 }; # base-type
a15dff8d 514
fd542f49 515subtype 'Undef' => as 'Item' => where { !defined($_) };
516subtype 'Defined' => as 'Item' => where { defined($_) };
a15dff8d 517
8ecb1fa0 518subtype 'Bool'
e85d2a5d 519 => as 'Item'
8ecb1fa0 520 => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
5a4c5493 521
e85d2a5d 522subtype 'Value'
523 => as 'Defined'
524 => where { !ref($_) }
28ffb449 525 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Value;
e85d2a5d 526
8ecb1fa0 527subtype 'Ref'
e85d2a5d 528 => as 'Defined'
529 => where { ref($_) }
28ffb449 530 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Ref;
8ecb1fa0 531
e85d2a5d 532subtype 'Str'
533 => as 'Value'
534 => where { 1 }
28ffb449 535 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Str;
8ecb1fa0 536
e85d2a5d 537subtype 'Num'
538 => as 'Value'
539 => where { Scalar::Util::looks_like_number($_) }
28ffb449 540 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Num;
e85d2a5d 541
542subtype 'Int'
543 => as 'Num'
8ecb1fa0 544 => where { "$_" =~ /^-?[0-9]+$/ }
28ffb449 545 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Int;
8ecb1fa0 546
28ffb449 547subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::ScalarRef;
28ffb449 548subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::CodeRef;
549subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::RegexpRef;
550subtype 'GlobRef' => as 'Ref' => where { ref($_) eq 'GLOB' } => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::GlobRef;
a15dff8d 551
0a5bd159 552# NOTE:
e85d2a5d 553# scalar filehandles are GLOB refs,
0a5bd159 554# but a GLOB ref is not always a filehandle
e85d2a5d 555subtype 'FileHandle'
556 => as 'GlobRef'
128c601e 557 => where { Scalar::Util::openhandle($_) || ( blessed($_) && $_->isa("IO::Handle") ) }
28ffb449 558 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::FileHandle;
0a5bd159 559
e85d2a5d 560# NOTE:
a15dff8d 561# blessed(qr/.../) returns true,.. how odd
e85d2a5d 562subtype 'Object'
563 => as 'Ref'
8ecb1fa0 564 => where { blessed($_) && blessed($_) ne 'Regexp' }
28ffb449 565 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Object;
a15dff8d 566
e85d2a5d 567subtype 'Role'
568 => as 'Object'
8ecb1fa0 569 => where { $_->can('does') }
28ffb449 570 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::Role;
e85d2a5d 571
0e0709ea 572my $_class_name_checker = sub {
0e0709ea 573};
574
e85d2a5d 575subtype 'ClassName'
576 => as 'Str'
e151db23 577 => where { Class::MOP::is_class_loaded($_) }
578 => optimize_as \&Moose::Util::TypeConstraints::OptimizedConstraints::ClassName;
02a0fb52 579
d9b40005 580## --------------------------------------------------------
7e4e1ad4 581# parameterizable types ...
582
583$REGISTRY->add_type_constraint(
584 Moose::Meta::TypeConstraint::Parameterizable->new(
585 name => 'ArrayRef',
586 package_defined_in => __PACKAGE__,
587 parent => find_type_constraint('Ref'),
588 constraint => sub { ref($_) eq 'ARRAY' },
589 optimized => \&Moose::Util::TypeConstraints::OptimizedConstraints::ArrayRef,
590 constraint_generator => sub {
591 my $type_parameter = shift;
dabed765 592 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 593 return sub {
594 foreach my $x (@$_) {
dabed765 595 ($check->($x)) || return
7e4e1ad4 596 } 1;
597 }
598 }
599 )
600);
601
602$REGISTRY->add_type_constraint(
603 Moose::Meta::TypeConstraint::Parameterizable->new(
604 name => 'HashRef',
605 package_defined_in => __PACKAGE__,
606 parent => find_type_constraint('Ref'),
607 constraint => sub { ref($_) eq 'HASH' },
608 optimized => \&Moose::Util::TypeConstraints::OptimizedConstraints::HashRef,
609 constraint_generator => sub {
4ab662d6 610 my $type_parameter = shift;
dabed765 611 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 612 return sub {
613 foreach my $x (values %$_) {
dabed765 614 ($check->($x)) || return
7e4e1ad4 615 } 1;
616 }
617 }
618 )
619);
620
621$REGISTRY->add_type_constraint(
622 Moose::Meta::TypeConstraint::Parameterizable->new(
623 name => 'Maybe',
624 package_defined_in => __PACKAGE__,
625 parent => find_type_constraint('Item'),
626 constraint => sub { 1 },
627 constraint_generator => sub {
4ab662d6 628 my $type_parameter = shift;
dabed765 629 my $check = $type_parameter->_compiled_type_constraint;
7e4e1ad4 630 return sub {
dabed765 631 return 1 if not(defined($_)) || $check->($_);
7e4e1ad4 632 return;
633 }
634 }
635 )
636);
637
4ab662d6 638my @PARAMETERIZABLE_TYPES = map {
639 $REGISTRY->get_type_constraint($_)
7e4e1ad4 640} qw[ArrayRef HashRef Maybe];
641
642sub get_all_parameterizable_types { @PARAMETERIZABLE_TYPES }
4ab662d6 643sub add_parameterizable_type {
7e4e1ad4 644 my $type = shift;
645 (blessed $type && $type->isa('Moose::Meta::TypeConstraint::Parameterizable'))
c245d69b 646 || Moose->throw_error("Type must be a Moose::Meta::TypeConstraint::Parameterizable not $type");
7e4e1ad4 647 push @PARAMETERIZABLE_TYPES => $type;
4ab662d6 648}
7e4e1ad4 649
650## --------------------------------------------------------
d9b40005 651# end of built-in types ...
652## --------------------------------------------------------
653
943596a6 654{
655 my @BUILTINS = list_all_type_constraints();
656 sub list_all_builtin_type_constraints { @BUILTINS }
657}
658
a15dff8d 6591;
660
661__END__
662
663=pod
664
665=head1 NAME
666
e522431d 667Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 668
669=head1 SYNOPSIS
670
671 use Moose::Util::TypeConstraints;
672
2c0cbef7 673 type 'Num' => where { Scalar::Util::looks_like_number($_) };
e85d2a5d 674
675 subtype 'Natural'
e606ae5f 676 => as 'Int'
a15dff8d 677 => where { $_ > 0 };
e85d2a5d 678
679 subtype 'NaturalLessThanTen'
2c0cbef7 680 => as 'Natural'
79592a54 681 => where { $_ < 10 }
682 => message { "This number ($_) is not less than ten!" };
e85d2a5d 683
684 coerce 'Num'
2c0cbef7 685 => from 'Str'
e85d2a5d 686 => via { 0+$_ };
687
2c0cbef7 688 enum 'RGBColors' => qw(red green blue);
a15dff8d 689
690=head1 DESCRIPTION
691
e85d2a5d 692This module provides Moose with the ability to create custom type
693contraints to be used in attribute definition.
e522431d 694
6ba6d68c 695=head2 Important Caveat
696
e85d2a5d 697This is B<NOT> a type system for Perl 5. These are type constraints,
698and they are not used by Moose unless you tell it to. No type
699inference is performed, expression are not typed, etc. etc. etc.
6ba6d68c 700
e85d2a5d 701This is simply a means of creating small constraint functions which
e606ae5f 702can be used to simplify your own type-checking code, with the added
004222dc 703side benefit of making your intentions clearer through self-documentation.
6ba6d68c 704
2c0cbef7 705=head2 Slightly Less Important Caveat
706
004222dc 707It is B<always> a good idea to quote your type and subtype names.
708
e85d2a5d 709This is to prevent perl from trying to execute the call as an indirect
2c0cbef7 710object call. This issue only seems to come up when you have a subtype
e85d2a5d 711the same name as a valid class, but when the issue does arise it tends
712to be quite annoying to debug.
2c0cbef7 713
714So for instance, this:
e85d2a5d 715
2c0cbef7 716 subtype DateTime => as Object => where { $_->isa('DateTime') };
717
718will I<Just Work>, while this:
719
720 use DateTime;
721 subtype DateTime => as Object => where { $_->isa('DateTime') };
722
e85d2a5d 723will fail silently and cause many headaches. The simple way to solve
724this, as well as future proof your subtypes from classes which have
2c0cbef7 725yet to have been created yet, is to simply do this:
726
727 use DateTime;
d44714be 728 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 729
6ba6d68c 730=head2 Default Type Constraints
e522431d 731
e606ae5f 732This module also provides a simple hierarchy for Perl 5 types, here is
004222dc 733that hierarchy represented visually.
e522431d 734
735 Any
e85d2a5d 736 Item
5a4c5493 737 Bool
7e4e1ad4 738 Maybe[`a]
f65cb534 739 Undef
740 Defined
5a4c5493 741 Value
742 Num
743 Int
744 Str
9af1d28b 745 ClassName
5a4c5493 746 Ref
747 ScalarRef
7e4e1ad4 748 ArrayRef[`a]
749 HashRef[`a]
5a4c5493 750 CodeRef
751 RegexpRef
3f7376b0 752 GlobRef
0a5bd159 753 FileHandle
e85d2a5d 754 Object
5a4c5493 755 Role
e522431d 756
4ab662d6 757B<NOTE:> Any type followed by a type parameter C<[`a]> can be
7e4e1ad4 758parameterized, this means you can say:
759
760 ArrayRef[Int] # an array of intergers
761 HashRef[CodeRef] # a hash of str to CODE ref mappings
762 Maybe[Str] # value may be a string, may be undefined
763
e606ae5f 764B<NOTE:> Unless you parameterize a type, then it is invalid to
765include the square brackets. I.e. C<ArrayRef[]> will be
766literally interpreted as a type name.
767
4ab662d6 768B<NOTE:> The C<Undef> type constraint for the most part works
769correctly now, but edge cases may still exist, please use it
7e4e1ad4 770sparringly.
703e92fb 771
7e4e1ad4 772B<NOTE:> The C<ClassName> type constraint does a complex package
4ab662d6 773existence check. This means that your class B<must> be loaded for
774this type constraint to pass. I know this is not ideal for all,
7e4e1ad4 775but it is a saner restriction than most others.
9af1d28b 776
e606ae5f 777=head2 Type Constraint Naming
004222dc 778
e606ae5f 779Since the types created by this module are global, it is suggested
780that you namespace your types just as you would namespace your
004222dc 781modules. So instead of creating a I<Color> type for your B<My::Graphics>
782module, you would call the type I<My::Graphics::Color> instead.
783
703e92fb 784=head2 Use with Other Constraint Modules
785
e85d2a5d 786This module should play fairly nicely with other constraint
787modules with only some slight tweaking. The C<where> clause
703e92fb 788in types is expected to be a C<CODE> reference which checks
004222dc 789it's first argument and returns a boolean. Since most constraint
e85d2a5d 790modules work in a similar way, it should be simple to adapt
703e92fb 791them to work with Moose.
792
e85d2a5d 793For instance, this is how you could use it with
794L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 795
e85d2a5d 796 type 'HashOfArrayOfObjects'
703e92fb 797 => IsHashRef(
798 -keys => HasLength,
799 -values => IsArrayRef( IsObject ));
800
e606ae5f 801For more examples see the F<t/200_examples/204_example_w_DCS.t>
004222dc 802test file.
703e92fb 803
e85d2a5d 804Here is an example of using L<Test::Deep> and it's non-test
805related C<eq_deeply> function.
703e92fb 806
e85d2a5d 807 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 808 => where {
e85d2a5d 809 eq_deeply($_,
703e92fb 810 array_each(subhashof({
811 bar => isa('Bar'),
812 random_number => ignore()
e85d2a5d 813 })))
703e92fb 814 };
815
e606ae5f 816For a complete example see the
004222dc 817F<t/200_examples/205_example_w_TestDeep.t> test file.
e85d2a5d 818
a15dff8d 819=head1 FUNCTIONS
820
821=head2 Type Constraint Constructors
822
e85d2a5d 823The following functions are used to create type constraints.
824They will then register the type constraints in a global store
825where Moose can get to them if it needs to.
a15dff8d 826
25f2c3fc 827See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 828
6ba6d68c 829=over 4
a15dff8d 830
6ba6d68c 831=item B<type ($name, $where_clause)>
a15dff8d 832
e85d2a5d 833This creates a base type, which has no parent.
a15dff8d 834
79592a54 835=item B<subtype ($name, $parent, $where_clause, ?$message)>
182134e8 836
e85d2a5d 837This creates a named subtype.
d6e2d9a1 838
79592a54 839=item B<subtype ($parent, $where_clause, ?$message)>
182134e8 840
e85d2a5d 841This creates an unnamed subtype and will return the type
842constraint meta-object, which will be an instance of
843L<Moose::Meta::TypeConstraint>.
a15dff8d 844
620db045 845=item B<class_type ($class, ?$options)>
3fef8ce8 846
847Creates a type constraint with the name C<$class> and the metaclass
848L<Moose::Meta::TypeConstraint::Class>.
849
620db045 850=item B<role_type ($role, ?$options)>
851
852Creates a type constraint with the name C<$role> and the metaclass
853L<Moose::Meta::TypeConstraint::Role>.
854
fcec2383 855=item B<enum ($name, @values)>
856
e85d2a5d 857This will create a basic subtype for a given set of strings.
858The resulting constraint will be a subtype of C<Str> and
4ce56d04 859will match any of the items in C<@values>. It is case sensitive.
860See the L<SYNOPSIS> for a simple example.
2c0cbef7 861
e85d2a5d 862B<NOTE:> This is not a true proper enum type, it is simple
2c0cbef7 863a convient constraint builder.
864
9f4334a1 865=item B<enum (\@values)>
866
4ab662d6 867If passed an ARRAY reference instead of the C<$name>, C<@values> pair,
9f4334a1 868this will create an unnamed enum. This can then be used in an attribute
869definition like so:
870
871 has 'sort_order' => (
872 is => 'ro',
4ab662d6 873 isa => enum([qw[ ascending descending ]]),
9f4334a1 874 );
875
6ba6d68c 876=item B<as>
a15dff8d 877
6ba6d68c 878This is just sugar for the type constraint construction syntax.
a15dff8d 879
6ba6d68c 880=item B<where>
a15dff8d 881
6ba6d68c 882This is just sugar for the type constraint construction syntax.
76d37e5a 883
e606ae5f 884Takes a block/code ref as an argument. When the type constraint is
885tested, the supplied code is run with the value to be tested in
886$_. This block should return true or false to indicate whether or not
887the constraint check passed.
888
76d37e5a 889=item B<message>
890
891This is just sugar for the type constraint construction syntax.
a15dff8d 892
e606ae5f 893Takes a block/code ref as an argument. When the type constraint fails,
894then the code block is run (with the value provided in $_). This code
895ref should return a string, which will be used in the text of the
896exception thrown.
897
8ecb1fa0 898=item B<optimize_as>
899
e85d2a5d 900This can be used to define a "hand optimized" version of your
d44714be 901type constraint which can be used to avoid traversing a subtype
e85d2a5d 902constraint heirarchy.
d44714be 903
e85d2a5d 904B<NOTE:> You should only use this if you know what you are doing,
905all the built in types use this, so your subtypes (assuming they
d44714be 906are shallow) will not likely need to use this.
907
6ba6d68c 908=back
a15dff8d 909
6ba6d68c 910=head2 Type Coercion Constructors
a15dff8d 911
e85d2a5d 912Type constraints can also contain type coercions as well. If you
913ask your accessor to coerce, then Moose will run the type-coercion
914code first, followed by the type constraint check. This feature
915should be used carefully as it is very powerful and could easily
587ae0d2 916take off a limb if you are not careful.
a15dff8d 917
25f2c3fc 918See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 919
6ba6d68c 920=over 4
a15dff8d 921
6ba6d68c 922=item B<coerce>
a15dff8d 923
6ba6d68c 924=item B<from>
a15dff8d 925
6ba6d68c 926This is just sugar for the type coercion construction syntax.
927
928=item B<via>
a15dff8d 929
6ba6d68c 930This is just sugar for the type coercion construction syntax.
a15dff8d 931
932=back
933
004222dc 934=head2 Type Constraint Construction & Locating
935
936=over 4
937
eb4c4e82 938=item B<normalize_type_constraint_name ($type_constraint_name)>
939
940Given a string that is expected to match a type constraint, will normalize the
941string so that extra whitespace and newlines are removed.
942
004222dc 943=item B<create_type_constraint_union ($pipe_seperated_types | @type_constraint_names)>
944
945Given string with C<$pipe_seperated_types> or a list of C<@type_constraint_names>,
946this will return a L<Moose::Meta::TypeConstraint::Union> instance.
947
948=item B<create_parameterized_type_constraint ($type_name)>
949
950Given a C<$type_name> in the form of:
951
952 BaseType[ContainerType]
953
954this will extract the base type and container type and build an instance of
955L<Moose::Meta::TypeConstraint::Parameterized> for it.
956
620db045 957=item B<create_class_type_constraint ($class, ?$options)>
004222dc 958
959Given a class name it will create a new L<Moose::Meta::TypeConstraint::Class>
960object for that class name.
961
620db045 962=item B<create_role_type_constraint ($role, ?$options)>
963
964Given a role name it will create a new L<Moose::Meta::TypeConstraint::Role>
965object for that role name.
966
dabed765 967=item B<create_enum_type_constraint ($name, $values)>
968
620db045 969=item B<find_or_parse_type_constraint ($type_name)>
004222dc 970
971This will attempt to find or create a type constraint given the a C<$type_name>.
972If it cannot find it in the registry, it will see if it should be a union or
620db045 973container type an create one if appropriate
974
975=item B<find_or_create_type_constraint ($type_name, ?$options_for_anon_type)>
976
977This function will first call C<find_or_parse_type_constraint> with the type name.
978
979If no type is found or created, but C<$options_for_anon_type> are provided, it
980will create the corresponding type.
981
982This was used by the C<does> and C<isa> parameters to L<Moose::Meta::Attribute>
983and are now superseded by C<find_or_create_isa_type_constraint> and
984C<find_or_create_does_type_constraint>.
985
986=item B<find_or_create_isa_type_constraint ($type_name)>
987
988=item B<find_or_create_does_type_constraint ($type_name)>
989
990Attempts to parse the type name using L<find_or_parse_type_constraint> and if
991no appropriate constraint is found will create a new anonymous one.
992
993The C<isa> variant will use C<create_class_type_constraint> and the C<does>
994variant will use C<create_role_type_constraint>.
004222dc 995
996=item B<find_type_constraint ($type_name)>
997
998This function can be used to locate a specific type constraint
999meta-object, of the class L<Moose::Meta::TypeConstraint> or a
1000derivative. What you do with it from there is up to you :)
1001
1002=item B<register_type_constraint ($type_object)>
1003
1004This function will register a named type constraint with the type registry.
1005
1006=item B<get_type_constraint_registry>
1007
1008Fetch the L<Moose::Meta::TypeConstraint::Registry> object which
1009keeps track of all type constraints.
1010
1011=item B<list_all_type_constraints>
1012
1013This will return a list of type constraint names, you can then
1014fetch them using C<find_type_constraint ($type_name)> if you
1015want to.
1016
1017=item B<list_all_builtin_type_constraints>
1018
1019This will return a list of builtin type constraints, meaning,
1020those which are defined in this module. See the section
1021labeled L<Default Type Constraints> for a complete list.
1022
1023=item B<export_type_constraints_as_functions>
1024
1025This will export all the current type constraints as functions
1026into the caller's namespace. Right now, this is mostly used for
1027testing, but it might prove useful to others.
1028
1029=item B<get_all_parameterizable_types>
1030
1031This returns all the parameterizable types that have been registered.
1032
1033=item B<add_parameterizable_type ($type)>
1034
1035Adds C<$type> to the list of parameterizable types
1036
1037=back
1038
998a8a25 1039=head1 Error Management
1040
1041=over 4
1042
1043=item B<confess>
1044
1045If the caller is a Moose metaclass, use its L<Moose::Meta::Class/throw_error>
1046routine, otherwise use L<Carp/confess>.
1047
1048=back
1049
571dd39f 1050=head2 Namespace Management
1051
1052=over 4
1053
1054=item B<unimport>
1055
e85d2a5d 1056This will remove all the type constraint keywords from the
571dd39f 1057calling class namespace.
1058
1059=back
1060
a15dff8d 1061=head1 BUGS
1062
e85d2a5d 1063All complex software has bugs lurking in it, and this module is no
a15dff8d 1064exception. If you find a bug please either email me, or add the bug
1065to cpan-RT.
1066
a15dff8d 1067=head1 AUTHOR
1068
1069Stevan Little E<lt>stevan@iinteractive.comE<gt>
1070
1071=head1 COPYRIGHT AND LICENSE
1072
778db3ac 1073Copyright 2006-2008 by Infinity Interactive, Inc.
a15dff8d 1074
1075L<http://www.iinteractive.com>
1076
1077This library is free software; you can redistribute it and/or modify
e85d2a5d 1078it under the same terms as Perl itself.
a15dff8d 1079
81dc201f 1080=cut