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