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