docs
[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';
a15dff8d 8use Scalar::Util 'blessed';
9
2c0cbef7 10our $VERSION = '0.07';
a15dff8d 11
4e036ee4 12use Moose::Meta::TypeConstraint;
2ca63f5d 13use Moose::Meta::TypeCoercion;
4e036ee4 14
2c0cbef7 15use Sub::Exporter
16 -setup => {
17 exports => qw[type subtype as where message coerce from via find_type_constraint enum],
18 groups => {
19 default => [':all']
a3c7e2fe 20 }
2c0cbef7 21 }
22);
a15dff8d 23
182134e8 24{
25 my %TYPES;
2c0cbef7 26 sub find_type_constraint ($) {
446e850f 27 return $TYPES{$_[0]}->[1]
28 if exists $TYPES{$_[0]};
29 return;
30 }
31
32 sub _dump_type_constraints {
33 require Data::Dumper;
256903b6 34 Data::Dumper::Dumper(\%TYPES);
446e850f 35 }
36
2c0cbef7 37 sub _create_type_constraint ($$$;$) {
76d37e5a 38 my ($name, $parent, $check, $message) = @_;
0e6614c3 39 my $pkg_defined_in = scalar(caller(1));
40 ($TYPES{$name}->[0] eq $pkg_defined_in)
446e850f 41 || confess "The type constraint '$name' has already been created "
0e6614c3 42 if defined $name && exists $TYPES{$name};
43 $parent = find_type_constraint($parent) if defined $parent;
a27aa600 44 my $constraint = Moose::Meta::TypeConstraint->new(
45 name => $name || '__ANON__',
66811d63 46 parent => $parent,
76d37e5a 47 constraint => $check,
48 message => $message,
4e036ee4 49 );
0e6614c3 50 $TYPES{$name} = [ $pkg_defined_in, $constraint ] if defined $name;
a27aa600 51 return $constraint;
182134e8 52 }
182134e8 53
2c0cbef7 54 sub _install_type_coercions ($$) {
a27aa600 55 my ($type_name, $coercion_map) = @_;
0e6614c3 56 my $type = find_type_constraint($type_name);
4e036ee4 57 (!$type->has_coercion)
d46a48f3 58 || confess "The type coercion for '$type_name' has already been registered";
a27aa600 59 my $type_coercion = Moose::Meta::TypeCoercion->new(
60 type_coercion_map => $coercion_map,
61 type_constraint => $type
62 );
63 $type->coercion($type_coercion);
182134e8 64 }
66811d63 65
2c0cbef7 66 sub create_type_constraint_union (@) {
c07af9d2 67 my (@type_constraint_names) = @_;
68 return Moose::Meta::TypeConstraint->union(
69 map {
70 find_type_constraint($_)
71 } @type_constraint_names
72 );
73 }
74
66811d63 75 sub export_type_contstraints_as_functions {
76 my $pkg = caller();
77 no strict 'refs';
78 foreach my $constraint (keys %TYPES) {
0e6614c3 79 *{"${pkg}::${constraint}"} = find_type_constraint($constraint)->_compiled_type_constraint;
66811d63 80 }
81 }
182134e8 82}
a15dff8d 83
7c13858b 84# type constructors
a15dff8d 85
86sub type ($$) {
87 my ($name, $check) = @_;
7c13858b 88 _create_type_constraint($name, undef, $check);
a15dff8d 89}
90
76d37e5a 91sub subtype ($$;$$) {
92 unshift @_ => undef if scalar @_ <= 2;
2c0cbef7 93 goto &_create_type_constraint;
a15dff8d 94}
95
4b598ea3 96sub coerce ($@) {
66811d63 97 my ($type_name, @coercion_map) = @_;
7c13858b 98 _install_type_coercions($type_name, \@coercion_map);
182134e8 99}
100
76d37e5a 101sub as ($) { $_[0] }
102sub from ($) { $_[0] }
103sub where (&) { $_[0] }
104sub via (&) { $_[0] }
105sub message (&) { $_[0] }
a15dff8d 106
2c0cbef7 107sub enum ($;@) {
fcec2383 108 my ($type_name, @values) = @_;
2c0cbef7 109 (scalar @values >= 2)
110 || confess "You must have at least two values to enumerate through";
fcec2383 111 my $regexp = join '|' => @values;
112 _create_type_constraint(
113 $type_name,
114 'Str',
115 sub { qr/^$regexp$/i }
116 );
117}
118
a15dff8d 119# define some basic types
120
f65cb534 121type 'Any' => where { 1 }; # meta-type including all
122type 'Item' => where { 1 }; # base-type
a15dff8d 123
f65cb534 124subtype 'Undef' => as 'Item' => where { !defined($_) };
125subtype 'Defined' => as 'Item' => where { defined($_) };
a15dff8d 126
81dc201f 127subtype 'Bool' => as 'Item' => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' };
5204cd52 128
5a4c5493 129subtype 'Value' => as 'Defined' => where { !ref($_) };
130subtype 'Ref' => as 'Defined' => where { ref($_) };
131
132subtype 'Str' => as 'Value' => where { 1 };
a15dff8d 133
81dc201f 134subtype 'Num' => as 'Value' => where { Scalar::Util::looks_like_number($_) };
d4634ca2 135subtype 'Int' => as 'Num' => where { "$_" =~ /^-?[0-9]+$/ };
81dc201f 136
137subtype 'ScalarRef' => as 'Ref' => where { ref($_) eq 'SCALAR' };
451c8248 138subtype 'ArrayRef' => as 'Ref' => where { ref($_) eq 'ARRAY' };
139subtype 'HashRef' => as 'Ref' => where { ref($_) eq 'HASH' };
e9ec68d6 140subtype 'CodeRef' => as 'Ref' => where { ref($_) eq 'CODE' };
141subtype 'RegexpRef' => as 'Ref' => where { ref($_) eq 'Regexp' };
a15dff8d 142
143# NOTE:
144# blessed(qr/.../) returns true,.. how odd
e9ec68d6 145subtype 'Object' => as 'Ref' => where { blessed($_) && blessed($_) ne 'Regexp' };
a15dff8d 146
02a0fb52 147subtype 'Role' => as 'Object' => where { $_->can('does') };
148
a15dff8d 1491;
150
151__END__
152
153=pod
154
155=head1 NAME
156
e522431d 157Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 158
159=head1 SYNOPSIS
160
161 use Moose::Util::TypeConstraints;
162
2c0cbef7 163 type 'Num' => where { Scalar::Util::looks_like_number($_) };
a15dff8d 164
2c0cbef7 165 subtype 'Natural'
166 => as 'Num'
a15dff8d 167 => where { $_ > 0 };
168
2c0cbef7 169 subtype 'NaturalLessThanTen'
170 => as 'Natural'
79592a54 171 => where { $_ < 10 }
172 => message { "This number ($_) is not less than ten!" };
6b8bd8d3 173
2c0cbef7 174 coerce 'Num'
175 => from 'Str'
d6e2d9a1 176 => via { 0+$_ };
98aae381 177
2c0cbef7 178 enum 'RGBColors' => qw(red green blue);
a15dff8d 179
180=head1 DESCRIPTION
181
e522431d 182This module provides Moose with the ability to create type contraints
183to be are used in both attribute definitions and for method argument
184validation.
185
6ba6d68c 186=head2 Important Caveat
187
188This is B<NOT> a type system for Perl 5. These are type constraints,
189and they are not used by Moose unless you tell it to. No type
190inference is performed, expression are not typed, etc. etc. etc.
191
192This is simply a means of creating small constraint functions which
a7d0cd00 193can be used to simplify your own type-checking code.
6ba6d68c 194
2c0cbef7 195=head2 Slightly Less Important Caveat
196
197It is almost always a good idea to quote your type and subtype names.
198This is to prevent perl from trying to create the call as an indirect
199object call. This issue only seems to come up when you have a subtype
200the same name as a valid class, but when the issue does arise it tends
201to be quite annoying to debug.
202
203So for instance, this:
204
205 subtype DateTime => as Object => where { $_->isa('DateTime') };
206
207will I<Just Work>, while this:
208
209 use DateTime;
210 subtype DateTime => as Object => where { $_->isa('DateTime') };
211
212will fail silently and cause many headaches. The simple way to solve
213this, as well as future proof your subtypes from classes which have
214yet to have been created yet, is to simply do this:
215
216 use DateTime;
217 subtype 'DateTime' => as Object => where { $_->isa('DateTime') };
218
6ba6d68c 219=head2 Default Type Constraints
e522431d 220
e522431d 221This module also provides a simple hierarchy for Perl 5 types, this
222could probably use some work, but it works for me at the moment.
223
224 Any
f65cb534 225 Item
5a4c5493 226 Bool
f65cb534 227 Undef
228 Defined
5a4c5493 229 Value
230 Num
231 Int
232 Str
233 Ref
234 ScalarRef
451c8248 235 ArrayRef
236 HashRef
5a4c5493 237 CodeRef
238 RegexpRef
239 Object
240 Role
e522431d 241
6ba6d68c 242Suggestions for improvement are welcome.
2c0cbef7 243
244B<NOTE:> The C<Undef> type constraint does not work correctly
245in every occasion, please use it sparringly.
e522431d 246
a15dff8d 247=head1 FUNCTIONS
248
182134e8 249=head2 Type Constraint Registry
250
251=over 4
252
253=item B<find_type_constraint ($type_name)>
254
6ba6d68c 255This function can be used to locate a specific type constraint
256meta-object. What you do with it from there is up to you :)
182134e8 257
c07af9d2 258=item B<create_type_constraint_union (@type_constraint_names)>
259
260Given a list of C<@type_constraint_names>, this will return a
261B<Moose::Meta::TypeConstraint::Union> instance.
262
182134e8 263=item B<export_type_contstraints_as_functions>
264
6ba6d68c 265This will export all the current type constraints as functions
266into the caller's namespace. Right now, this is mostly used for
267testing, but it might prove useful to others.
268
182134e8 269=back
270
a15dff8d 271=head2 Type Constraint Constructors
272
6ba6d68c 273The following functions are used to create type constraints.
274They will then register the type constraints in a global store
275where Moose can get to them if it needs to.
a15dff8d 276
6ba6d68c 277See the L<SYNOPOSIS> for an example of how to use these.
a15dff8d 278
6ba6d68c 279=over 4
a15dff8d 280
6ba6d68c 281=item B<type ($name, $where_clause)>
a15dff8d 282
6ba6d68c 283This creates a base type, which has no parent.
a15dff8d 284
79592a54 285=item B<subtype ($name, $parent, $where_clause, ?$message)>
182134e8 286
6ba6d68c 287This creates a named subtype.
d6e2d9a1 288
79592a54 289=item B<subtype ($parent, $where_clause, ?$message)>
182134e8 290
6ba6d68c 291This creates an unnamed subtype and will return the type
292constraint meta-object, which will be an instance of
293L<Moose::Meta::TypeConstraint>.
a15dff8d 294
fcec2383 295=item B<enum ($name, @values)>
296
2c0cbef7 297This will create a basic subtype for a given set of strings.
298The resulting constraint will be a subtype of C<Str> and
299will match any of the items in C<@values>. See the L<SYNOPSIS>
300for a simple example.
301
302B<NOTE:> This is not a true proper enum type, it is simple
303a convient constraint builder.
304
6ba6d68c 305=item B<as>
a15dff8d 306
6ba6d68c 307This is just sugar for the type constraint construction syntax.
a15dff8d 308
6ba6d68c 309=item B<where>
a15dff8d 310
6ba6d68c 311This is just sugar for the type constraint construction syntax.
76d37e5a 312
313=item B<message>
314
315This is just sugar for the type constraint construction syntax.
a15dff8d 316
6ba6d68c 317=back
a15dff8d 318
6ba6d68c 319=head2 Type Coercion Constructors
a15dff8d 320
6ba6d68c 321Type constraints can also contain type coercions as well. In most
322cases Moose will run the type-coercion code first, followed by the
323type constraint check. This feature should be used carefully as it
324is very powerful and could easily take off a limb if you are not
325careful.
a15dff8d 326
6ba6d68c 327See the L<SYNOPOSIS> for an example of how to use these.
a15dff8d 328
6ba6d68c 329=over 4
a15dff8d 330
6ba6d68c 331=item B<coerce>
a15dff8d 332
6ba6d68c 333=item B<from>
a15dff8d 334
6ba6d68c 335This is just sugar for the type coercion construction syntax.
336
337=item B<via>
a15dff8d 338
6ba6d68c 339This is just sugar for the type coercion construction syntax.
a15dff8d 340
341=back
342
343=head1 BUGS
344
345All complex software has bugs lurking in it, and this module is no
346exception. If you find a bug please either email me, or add the bug
347to cpan-RT.
348
a15dff8d 349=head1 AUTHOR
350
351Stevan Little E<lt>stevan@iinteractive.comE<gt>
352
353=head1 COPYRIGHT AND LICENSE
354
355Copyright 2006 by Infinity Interactive, Inc.
356
357L<http://www.iinteractive.com>
358
359This library is free software; you can redistribute it and/or modify
360it under the same terms as Perl itself.
361
81dc201f 362=cut