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