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