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