uploadin
[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 Sub::Name 'subname';
9use Scalar::Util 'blessed';
10
5569c072 11our $VERSION = '0.02';
a15dff8d 12
13sub import {
14 shift;
15 my $pkg = shift || caller();
16 return if $pkg eq ':no_export';
17 no strict 'refs';
4b598ea3 18 foreach my $export (qw(type subtype as where to coerce)) {
a15dff8d 19 *{"${pkg}::${export}"} = \&{"${export}"};
a15dff8d 20 }
a15dff8d 21}
22
182134e8 23{
24 my %TYPES;
25 sub find_type_constraint {
26 my $type_name = shift;
27 $TYPES{$type_name};
28 }
29
30 sub register_type_constraint {
31 my ($type_name, $type_constraint) = @_;
32 $TYPES{$type_name} = $type_constraint;
33 }
34
4b598ea3 35 sub dump_type_constraints {
36 require Data::Dumper;
37 $Data::Dumper::Deparse = 1;
38 Data::Dumper::Dumper(\%TYPES);
39 }
40
182134e8 41 sub export_type_contstraints_as_functions {
42 my $pkg = caller();
43 no strict 'refs';
44 foreach my $constraint (keys %TYPES) {
45 *{"${pkg}::${constraint}"} = $TYPES{$constraint};
46 }
47 }
48}
49
50{
51 my %COERCIONS;
52 sub find_type_coercion {
53 my $type_name = shift;
54 $COERCIONS{$type_name};
55 }
56
57 sub register_type_coercion {
58 my ($type_name, $type_coercion) = @_;
59 $COERCIONS{$type_name} = $type_coercion;
60 }
61}
a15dff8d 62
a15dff8d 63
64sub type ($$) {
65 my ($name, $check) = @_;
182134e8 66 my $full_name = caller() . "::${name}";
67 register_type_constraint($name => subname $full_name => sub {
a15dff8d 68 local $_ = $_[0];
69 return undef unless $check->($_[0]);
70 $_[0];
182134e8 71 });
a15dff8d 72}
73
74sub subtype ($$;$) {
75 my ($name, $parent, $check) = @_;
76 if (defined $check) {
182134e8 77 my $full_name = caller() . "::${name}";
78 $parent = find_type_constraint($parent)
79 unless $parent && ref($parent) eq 'CODE';
6b8bd8d3 80 register_type_constraint($name => subname $full_name => sub {
a15dff8d 81 local $_ = $_[0];
82 return undef unless defined $parent->($_[0]) && $check->($_[0]);
83 $_[0];
182134e8 84 });
a15dff8d 85 }
86 else {
87 ($parent, $check) = ($name, $parent);
182134e8 88 $parent = find_type_constraint($parent)
89 unless $parent && ref($parent) eq 'CODE';
90 return subname '__anon_subtype__' => sub {
a15dff8d 91 local $_ = $_[0];
92 return undef unless defined $parent->($_[0]) && $check->($_[0]);
93 $_[0];
5569c072 94 };
a15dff8d 95 }
96}
97
4b598ea3 98sub coerce ($@) {
e90c03d0 99 my ($type_name, @coercion_map) = @_;
4b598ea3 100 #use Data::Dumper;
101 #warn Dumper \@coercion_map;
e90c03d0 102 my @coercions;
103 while (@coercion_map) {
104 my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
105 my $constraint = find_type_constraint($constraint_name);
106 (defined $constraint)
107 || confess "Could not find the type constraint ($constraint_name)";
108 push @coercions => [ $constraint, $action ];
109 }
182134e8 110 register_type_coercion($type_name, sub {
e90c03d0 111 my $thing = shift;
112 foreach my $coercion (@coercions) {
113 my ($constraint, $converter) = @$coercion;
114 if (defined $constraint->($thing)) {
115 return $converter->($thing);
116 }
117 }
118 return $thing;
182134e8 119 });
120}
121
a15dff8d 122sub as ($) { $_[0] }
123sub where (&) { $_[0] }
182134e8 124sub to (&) { $_[0] }
a15dff8d 125
126# define some basic types
127
128type Any => where { 1 };
129
130type Value => where { !ref($_) };
131type Ref => where { ref($_) };
132
133subtype Int => as Value => where { Scalar::Util::looks_like_number($_) };
134subtype Str => as Value => where { !Scalar::Util::looks_like_number($_) };
135
136subtype ScalarRef => as Ref => where { ref($_) eq 'SCALAR' };
137subtype ArrayRef => as Ref => where { ref($_) eq 'ARRAY' };
138subtype HashRef => as Ref => where { ref($_) eq 'HASH' };
139subtype CodeRef => as Ref => where { ref($_) eq 'CODE' };
140subtype RegexpRef => as Ref => where { ref($_) eq 'Regexp' };
141
142# NOTE:
143# blessed(qr/.../) returns true,.. how odd
144subtype Object => as Ref => where { blessed($_) && blessed($_) ne 'Regexp' };
145
1461;
147
148__END__
149
150=pod
151
152=head1 NAME
153
e522431d 154Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 155
156=head1 SYNOPSIS
157
158 use Moose::Util::TypeConstraints;
159
160 type Num => where { Scalar::Util::looks_like_number($_) };
161
162 subtype Natural
163 => as Num
164 => where { $_ > 0 };
165
166 subtype NaturalLessThanTen
167 => as Natural
168 => where { $_ < 10 };
6b8bd8d3 169
170 coerce Num
171 => as Str
172 => to { 0+$_ };
a15dff8d 173
174=head1 DESCRIPTION
175
e522431d 176This module provides Moose with the ability to create type contraints
177to be are used in both attribute definitions and for method argument
178validation.
179
180This is B<NOT> a type system for Perl 5.
181
e522431d 182This module also provides a simple hierarchy for Perl 5 types, this
183could probably use some work, but it works for me at the moment.
184
185 Any
186 Value
187 Int
188 Str
189 Ref
190 ScalarRef
191 ArrayRef
192 HashRef
193 CodeRef
194 RegexpRef
195 Object
196
197Suggestions for improvement are welcome.
198
a15dff8d 199=head1 FUNCTIONS
200
182134e8 201=head2 Type Constraint Registry
202
203=over 4
204
205=item B<find_type_constraint ($type_name)>
206
207=item B<register_type_constraint ($type_name, $type_constraint)>
208
209=item B<find_type_coercion>
210
211=item B<register_type_coercion>
212
213=item B<export_type_contstraints_as_functions>
214
4b598ea3 215=item B<dump_type_constraints>
216
182134e8 217=back
218
a15dff8d 219=head2 Type Constraint Constructors
220
221=over 4
222
223=item B<type>
224
225=item B<subtype>
226
227=item B<as>
228
229=item B<where>
230
182134e8 231=item B<coerce>
232
233=item B<to>
234
a15dff8d 235=back
236
237=head2 Built-in Type Constraints
238
239=over 4
240
241=item B<Any>
242
243=item B<Value>
244
245=item B<Int>
246
247=item B<Str>
248
249=item B<Ref>
250
251=item B<ArrayRef>
252
253=item B<CodeRef>
254
255=item B<HashRef>
256
257=item B<RegexpRef>
258
259=item B<ScalarRef>
260
261=item B<Object>
262
263=back
264
265=head1 BUGS
266
267All complex software has bugs lurking in it, and this module is no
268exception. If you find a bug please either email me, or add the bug
269to cpan-RT.
270
a15dff8d 271=head1 AUTHOR
272
273Stevan Little E<lt>stevan@iinteractive.comE<gt>
274
275=head1 COPYRIGHT AND LICENSE
276
277Copyright 2006 by Infinity Interactive, Inc.
278
279L<http://www.iinteractive.com>
280
281This library is free software; you can redistribute it and/or modify
282it under the same terms as Perl itself.
283
284=cut