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