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