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