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