doc updates
[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
004222dc 635can be used to simplify your own type-checking code, with the added
636side benefit of making your intentions clearer through self-documentation.
6ba6d68c 637
2c0cbef7 638=head2 Slightly Less Important Caveat
639
004222dc 640It is B<always> a good idea to quote your type and subtype names.
641
e85d2a5d 642This is to prevent perl from trying to execute the call as an indirect
2c0cbef7 643object call. This issue only seems to come up when you have a subtype
e85d2a5d 644the same name as a valid class, but when the issue does arise it tends
645to be quite annoying to debug.
2c0cbef7 646
647So for instance, this:
e85d2a5d 648
2c0cbef7 649 subtype DateTime => as Object => where { $_->isa('DateTime') };
650
651will I<Just Work>, while this:
652
653 use DateTime;
654 subtype DateTime => as Object => where { $_->isa('DateTime') };
655
e85d2a5d 656will fail silently and cause many headaches. The simple way to solve
657this, as well as future proof your subtypes from classes which have
2c0cbef7 658yet to have been created yet, is to simply do this:
659
660 use DateTime;
d44714be 661 subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };
2c0cbef7 662
6ba6d68c 663=head2 Default Type Constraints
e522431d 664
004222dc 665This module also provides a simple hierarchy for Perl 5 types, here is
666that hierarchy represented visually.
e522431d 667
668 Any
e85d2a5d 669 Item
5a4c5493 670 Bool
7e4e1ad4 671 Maybe[`a]
f65cb534 672 Undef
673 Defined
5a4c5493 674 Value
675 Num
676 Int
677 Str
9af1d28b 678 ClassName
5a4c5493 679 Ref
680 ScalarRef
7e4e1ad4 681 ArrayRef[`a]
682 HashRef[`a]
5a4c5493 683 CodeRef
684 RegexpRef
3f7376b0 685 GlobRef
0a5bd159 686 FileHandle
e85d2a5d 687 Object
5a4c5493 688 Role
e522431d 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
004222dc 706=head2 Type Constraint Naming
707
708Since the types created by this module are global, it is suggested
709that you namespace your types just as you would namespace your
710modules. So instead of creating a I<Color> type for your B<My::Graphics>
711module, you would call the type I<My::Graphics::Color> instead.
712
703e92fb 713=head2 Use with Other Constraint Modules
714
e85d2a5d 715This module should play fairly nicely with other constraint
716modules with only some slight tweaking. The C<where> clause
703e92fb 717in types is expected to be a C<CODE> reference which checks
004222dc 718it's first argument and returns a boolean. Since most constraint
e85d2a5d 719modules work in a similar way, it should be simple to adapt
703e92fb 720them to work with Moose.
721
e85d2a5d 722For instance, this is how you could use it with
723L<Declare::Constraints::Simple> to declare a completely new type.
703e92fb 724
e85d2a5d 725 type 'HashOfArrayOfObjects'
703e92fb 726 => IsHashRef(
727 -keys => HasLength,
728 -values => IsArrayRef( IsObject ));
729
004222dc 730For more examples see the F<t/200_examples/204_example_w_DCS.t>
731test file.
703e92fb 732
e85d2a5d 733Here is an example of using L<Test::Deep> and it's non-test
734related C<eq_deeply> function.
703e92fb 735
e85d2a5d 736 type 'ArrayOfHashOfBarsAndRandomNumbers'
703e92fb 737 => where {
e85d2a5d 738 eq_deeply($_,
703e92fb 739 array_each(subhashof({
740 bar => isa('Bar'),
741 random_number => ignore()
e85d2a5d 742 })))
703e92fb 743 };
744
004222dc 745For a complete example see the
746F<t/200_examples/205_example_w_TestDeep.t> test file.
e85d2a5d 747
a15dff8d 748=head1 FUNCTIONS
749
750=head2 Type Constraint Constructors
751
e85d2a5d 752The following functions are used to create type constraints.
753They will then register the type constraints in a global store
754where Moose can get to them if it needs to.
a15dff8d 755
25f2c3fc 756See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 757
6ba6d68c 758=over 4
a15dff8d 759
6ba6d68c 760=item B<type ($name, $where_clause)>
a15dff8d 761
e85d2a5d 762This creates a base type, which has no parent.
a15dff8d 763
79592a54 764=item B<subtype ($name, $parent, $where_clause, ?$message)>
182134e8 765
e85d2a5d 766This creates a named subtype.
d6e2d9a1 767
79592a54 768=item B<subtype ($parent, $where_clause, ?$message)>
182134e8 769
e85d2a5d 770This creates an unnamed subtype and will return the type
771constraint meta-object, which will be an instance of
772L<Moose::Meta::TypeConstraint>.
a15dff8d 773
4ab662d6 774=item B<class_type ($class, ?$message)>
3fef8ce8 775
776Creates a type constraint with the name C<$class> and the metaclass
777L<Moose::Meta::TypeConstraint::Class>.
778
fcec2383 779=item B<enum ($name, @values)>
780
e85d2a5d 781This will create a basic subtype for a given set of strings.
782The resulting constraint will be a subtype of C<Str> and
4ce56d04 783will match any of the items in C<@values>. It is case sensitive.
784See the L<SYNOPSIS> for a simple example.
2c0cbef7 785
e85d2a5d 786B<NOTE:> This is not a true proper enum type, it is simple
2c0cbef7 787a convient constraint builder.
788
9f4334a1 789=item B<enum (\@values)>
790
4ab662d6 791If passed an ARRAY reference instead of the C<$name>, C<@values> pair,
9f4334a1 792this will create an unnamed enum. This can then be used in an attribute
793definition like so:
794
795 has 'sort_order' => (
796 is => 'ro',
4ab662d6 797 isa => enum([qw[ ascending descending ]]),
9f4334a1 798 );
799
6ba6d68c 800=item B<as>
a15dff8d 801
6ba6d68c 802This is just sugar for the type constraint construction syntax.
a15dff8d 803
6ba6d68c 804=item B<where>
a15dff8d 805
6ba6d68c 806This is just sugar for the type constraint construction syntax.
76d37e5a 807
808=item B<message>
809
810This is just sugar for the type constraint construction syntax.
a15dff8d 811
8ecb1fa0 812=item B<optimize_as>
813
e85d2a5d 814This can be used to define a "hand optimized" version of your
d44714be 815type constraint which can be used to avoid traversing a subtype
e85d2a5d 816constraint heirarchy.
d44714be 817
e85d2a5d 818B<NOTE:> You should only use this if you know what you are doing,
819all the built in types use this, so your subtypes (assuming they
d44714be 820are shallow) will not likely need to use this.
821
6ba6d68c 822=back
a15dff8d 823
6ba6d68c 824=head2 Type Coercion Constructors
a15dff8d 825
e85d2a5d 826Type constraints can also contain type coercions as well. If you
827ask your accessor to coerce, then Moose will run the type-coercion
828code first, followed by the type constraint check. This feature
829should be used carefully as it is very powerful and could easily
587ae0d2 830take off a limb if you are not careful.
a15dff8d 831
25f2c3fc 832See the L<SYNOPSIS> for an example of how to use these.
a15dff8d 833
6ba6d68c 834=over 4
a15dff8d 835
6ba6d68c 836=item B<coerce>
a15dff8d 837
6ba6d68c 838=item B<from>
a15dff8d 839
6ba6d68c 840This is just sugar for the type coercion construction syntax.
841
842=item B<via>
a15dff8d 843
6ba6d68c 844This is just sugar for the type coercion construction syntax.
a15dff8d 845
846=back
847
004222dc 848=head2 Type Constraint Construction & Locating
849
850=over 4
851
852=item B<create_type_constraint_union ($pipe_seperated_types | @type_constraint_names)>
853
854Given string with C<$pipe_seperated_types> or a list of C<@type_constraint_names>,
855this will return a L<Moose::Meta::TypeConstraint::Union> instance.
856
857=item B<create_parameterized_type_constraint ($type_name)>
858
859Given a C<$type_name> in the form of:
860
861 BaseType[ContainerType]
862
863this will extract the base type and container type and build an instance of
864L<Moose::Meta::TypeConstraint::Parameterized> for it.
865
866=item B<create_class_type_constraint ($class, ?$message)>
867
868Given a class name it will create a new L<Moose::Meta::TypeConstraint::Class>
869object for that class name.
870
871=item B<find_or_create_type_constraint ($type_name, ?$options_for_anon_type)>
872
873This will attempt to find or create a type constraint given the a C<$type_name>.
874If it cannot find it in the registry, it will see if it should be a union or
875container type an create one if appropriate, and lastly if nothing can be
876found or created that way, it will create an anon-type using the
877C<$options_for_anon_type> HASH ref to populate it. If the C<$options_for_anon_type>
878is not specified (it is C<undef>), then it will not create anything and simply
879return.
880
881=item B<find_type_constraint ($type_name)>
882
883This function can be used to locate a specific type constraint
884meta-object, of the class L<Moose::Meta::TypeConstraint> or a
885derivative. What you do with it from there is up to you :)
886
887=item B<register_type_constraint ($type_object)>
888
889This function will register a named type constraint with the type registry.
890
891=item B<get_type_constraint_registry>
892
893Fetch the L<Moose::Meta::TypeConstraint::Registry> object which
894keeps track of all type constraints.
895
896=item B<list_all_type_constraints>
897
898This will return a list of type constraint names, you can then
899fetch them using C<find_type_constraint ($type_name)> if you
900want to.
901
902=item B<list_all_builtin_type_constraints>
903
904This will return a list of builtin type constraints, meaning,
905those which are defined in this module. See the section
906labeled L<Default Type Constraints> for a complete list.
907
908=item B<export_type_constraints_as_functions>
909
910This will export all the current type constraints as functions
911into the caller's namespace. Right now, this is mostly used for
912testing, but it might prove useful to others.
913
914=item B<get_all_parameterizable_types>
915
916This returns all the parameterizable types that have been registered.
917
918=item B<add_parameterizable_type ($type)>
919
920Adds C<$type> to the list of parameterizable types
921
922=back
923
571dd39f 924=head2 Namespace Management
925
926=over 4
927
928=item B<unimport>
929
e85d2a5d 930This will remove all the type constraint keywords from the
571dd39f 931calling class namespace.
932
933=back
934
a15dff8d 935=head1 BUGS
936
e85d2a5d 937All complex software has bugs lurking in it, and this module is no
a15dff8d 938exception. If you find a bug please either email me, or add the bug
939to cpan-RT.
940
a15dff8d 941=head1 AUTHOR
942
943Stevan Little E<lt>stevan@iinteractive.comE<gt>
944
945=head1 COPYRIGHT AND LICENSE
946
778db3ac 947Copyright 2006-2008 by Infinity Interactive, Inc.
a15dff8d 948
949L<http://www.iinteractive.com>
950
951This library is free software; you can redistribute it and/or modify
e85d2a5d 952it under the same terms as Perl itself.
a15dff8d 953
81dc201f 954=cut