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 {
68 return find_type_constraint($name) unless defined $_[0];
a15dff8d 69 local $_ = $_[0];
70 return undef unless $check->($_[0]);
71 $_[0];
182134e8 72 });
a15dff8d 73}
74
75sub subtype ($$;$) {
76 my ($name, $parent, $check) = @_;
77 if (defined $check) {
182134e8 78 my $full_name = caller() . "::${name}";
79 $parent = find_type_constraint($parent)
80 unless $parent && ref($parent) eq 'CODE';
81 register_type_constraint($name => subname $full_name => sub {
82 return find_type_constraint($name) unless defined $_[0];
a15dff8d 83 local $_ = $_[0];
84 return undef unless defined $parent->($_[0]) && $check->($_[0]);
85 $_[0];
182134e8 86 });
a15dff8d 87 }
88 else {
89 ($parent, $check) = ($name, $parent);
182134e8 90 $parent = find_type_constraint($parent)
91 unless $parent && ref($parent) eq 'CODE';
92 return subname '__anon_subtype__' => sub {
a15dff8d 93 local $_ = $_[0];
94 return undef unless defined $parent->($_[0]) && $check->($_[0]);
95 $_[0];
5569c072 96 };
a15dff8d 97 }
98}
99
4b598ea3 100sub coerce ($@) {
e90c03d0 101 my ($type_name, @coercion_map) = @_;
4b598ea3 102 #use Data::Dumper;
103 #warn Dumper \@coercion_map;
e90c03d0 104 my @coercions;
105 while (@coercion_map) {
106 my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
107 my $constraint = find_type_constraint($constraint_name);
108 (defined $constraint)
109 || confess "Could not find the type constraint ($constraint_name)";
110 push @coercions => [ $constraint, $action ];
111 }
182134e8 112 register_type_coercion($type_name, sub {
e90c03d0 113 my $thing = shift;
114 foreach my $coercion (@coercions) {
115 my ($constraint, $converter) = @$coercion;
116 if (defined $constraint->($thing)) {
117 return $converter->($thing);
118 }
119 }
120 return $thing;
182134e8 121 });
122}
123
a15dff8d 124sub as ($) { $_[0] }
125sub where (&) { $_[0] }
182134e8 126sub to (&) { $_[0] }
a15dff8d 127
128# define some basic types
129
130type Any => where { 1 };
131
132type Value => where { !ref($_) };
133type Ref => where { ref($_) };
134
135subtype Int => as Value => where { Scalar::Util::looks_like_number($_) };
136subtype Str => as Value => where { !Scalar::Util::looks_like_number($_) };
137
138subtype ScalarRef => as Ref => where { ref($_) eq 'SCALAR' };
139subtype ArrayRef => as Ref => where { ref($_) eq 'ARRAY' };
140subtype HashRef => as Ref => where { ref($_) eq 'HASH' };
141subtype CodeRef => as Ref => where { ref($_) eq 'CODE' };
142subtype RegexpRef => as Ref => where { ref($_) eq 'Regexp' };
143
144# NOTE:
145# blessed(qr/.../) returns true,.. how odd
146subtype Object => as Ref => where { blessed($_) && blessed($_) ne 'Regexp' };
147
1481;
149
150__END__
151
152=pod
153
154=head1 NAME
155
e522431d 156Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 157
158=head1 SYNOPSIS
159
160 use Moose::Util::TypeConstraints;
161
162 type Num => where { Scalar::Util::looks_like_number($_) };
163
164 subtype Natural
165 => as Num
166 => where { $_ > 0 };
167
168 subtype NaturalLessThanTen
169 => as Natural
170 => where { $_ < 10 };
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
178This is B<NOT> a type system for Perl 5.
179
180The type and subtype constraints are basically functions which will
181validate their first argument. If called with no arguments, they will
182return themselves (this is syntactic sugar for Moose attributes).
183
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
188 Value
189 Int
190 Str
191 Ref
192 ScalarRef
193 ArrayRef
194 HashRef
195 CodeRef
196 RegexpRef
197 Object
198
199Suggestions for improvement are welcome.
200
a15dff8d 201=head1 FUNCTIONS
202
182134e8 203=head2 Type Constraint Registry
204
205=over 4
206
207=item B<find_type_constraint ($type_name)>
208
209=item B<register_type_constraint ($type_name, $type_constraint)>
210
211=item B<find_type_coercion>
212
213=item B<register_type_coercion>
214
215=item B<export_type_contstraints_as_functions>
216
4b598ea3 217=item B<dump_type_constraints>
218
182134e8 219=back
220
a15dff8d 221=head2 Type Constraint Constructors
222
223=over 4
224
225=item B<type>
226
227=item B<subtype>
228
229=item B<as>
230
231=item B<where>
232
182134e8 233=item B<coerce>
234
235=item B<to>
236
a15dff8d 237=back
238
239=head2 Built-in Type Constraints
240
241=over 4
242
243=item B<Any>
244
245=item B<Value>
246
247=item B<Int>
248
249=item B<Str>
250
251=item B<Ref>
252
253=item B<ArrayRef>
254
255=item B<CodeRef>
256
257=item B<HashRef>
258
259=item B<RegexpRef>
260
261=item B<ScalarRef>
262
263=item B<Object>
264
265=back
266
267=head1 BUGS
268
269All complex software has bugs lurking in it, and this module is no
270exception. If you find a bug please either email me, or add the bug
271to cpan-RT.
272
a15dff8d 273=head1 AUTHOR
274
275Stevan Little E<lt>stevan@iinteractive.comE<gt>
276
277=head1 COPYRIGHT AND LICENSE
278
279Copyright 2006 by Infinity Interactive, Inc.
280
281L<http://www.iinteractive.com>
282
283This library is free software; you can redistribute it and/or modify
284it under the same terms as Perl itself.
285
286=cut