cleaning up
[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
4e036ee4 13use Moose::Meta::TypeConstraint;
14
a15dff8d 15sub import {
16 shift;
17 my $pkg = shift || caller();
18 return if $pkg eq ':no_export';
19 no strict 'refs';
d6e2d9a1 20 foreach my $export (qw(type subtype as where coerce from via)) {
a15dff8d 21 *{"${pkg}::${export}"} = \&{"${export}"};
a15dff8d 22 }
a15dff8d 23}
24
182134e8 25{
26 my %TYPES;
82168dbb 27 sub find_type_constraint { $TYPES{$_[0]} }
182134e8 28
82168dbb 29 sub create_type_constraint {
66811d63 30 my ($name, $parent, $constraint) = @_;
31 (not exists $TYPES{$name})
82168dbb 32 || confess "The type constraint '$name' has already been created";
66811d63 33 $parent = find_type_constraint($parent) if defined $parent;
34 $TYPES{$name} = Moose::Meta::TypeConstraint->new(
35 name => $name,
36 parent => $parent,
37 constraint => $constraint,
4e036ee4 38 );
182134e8 39 }
182134e8 40
182134e8 41 sub find_type_coercion {
42 my $type_name = shift;
4e036ee4 43 $TYPES{$type_name}->coercion_code;
182134e8 44 }
45
46 sub register_type_coercion {
47 my ($type_name, $type_coercion) = @_;
4e036ee4 48 my $type = $TYPES{$type_name};
49 (!$type->has_coercion)
d46a48f3 50 || confess "The type coercion for '$type_name' has already been registered";
4e036ee4 51 $type->set_coercion_code($type_coercion);
182134e8 52 }
66811d63 53
54 sub export_type_contstraints_as_functions {
55 my $pkg = caller();
56 no strict 'refs';
57 foreach my $constraint (keys %TYPES) {
58 *{"${pkg}::${constraint}"} = $TYPES{$constraint}->constraint_code;
59 }
60 }
182134e8 61}
a15dff8d 62
a15dff8d 63
64sub type ($$) {
65 my ($name, $check) = @_;
82168dbb 66 create_type_constraint($name, undef, $check);
a15dff8d 67}
68
69sub subtype ($$;$) {
66811d63 70 if (scalar @_ == 3) {
71 my ($name, $parent, $check) = @_;
82168dbb 72 create_type_constraint($name, $parent, $check);
a15dff8d 73 }
74 else {
66811d63 75 my ($parent, $check) = @_;
76 $parent = find_type_constraint($parent);
77 return Moose::Meta::TypeConstraint->new(
78 name => '__ANON__',
79 parent => $parent,
80 constraint => $check,
81 );
a15dff8d 82 }
83}
84
4b598ea3 85sub coerce ($@) {
66811d63 86 my ($type_name, @coercion_map) = @_;
e90c03d0 87 my @coercions;
88 while (@coercion_map) {
89 my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
01bf4112 90 my $constraint = find_type_constraint($constraint_name)->constraint_code;
e90c03d0 91 (defined $constraint)
92 || confess "Could not find the type constraint ($constraint_name)";
93 push @coercions => [ $constraint, $action ];
94 }
182134e8 95 register_type_coercion($type_name, sub {
e90c03d0 96 my $thing = shift;
97 foreach my $coercion (@coercions) {
98 my ($constraint, $converter) = @$coercion;
99 if (defined $constraint->($thing)) {
b841b2a3 100 local $_ = $thing;
e90c03d0 101 return $converter->($thing);
102 }
103 }
104 return $thing;
182134e8 105 });
106}
107
a15dff8d 108sub as ($) { $_[0] }
d6e2d9a1 109sub from ($) { $_[0] }
a15dff8d 110sub where (&) { $_[0] }
d6e2d9a1 111sub via (&) { $_[0] }
a15dff8d 112
113# define some basic types
114
115type Any => where { 1 };
116
117type Value => where { !ref($_) };
118type Ref => where { ref($_) };
119
120subtype Int => as Value => where { Scalar::Util::looks_like_number($_) };
121subtype Str => as Value => where { !Scalar::Util::looks_like_number($_) };
122
123subtype ScalarRef => as Ref => where { ref($_) eq 'SCALAR' };
124subtype ArrayRef => as Ref => where { ref($_) eq 'ARRAY' };
125subtype HashRef => as Ref => where { ref($_) eq 'HASH' };
126subtype CodeRef => as Ref => where { ref($_) eq 'CODE' };
127subtype RegexpRef => as Ref => where { ref($_) eq 'Regexp' };
128
129# NOTE:
130# blessed(qr/.../) returns true,.. how odd
131subtype Object => as Ref => where { blessed($_) && blessed($_) ne 'Regexp' };
132
1331;
134
135__END__
136
137=pod
138
139=head1 NAME
140
e522431d 141Moose::Util::TypeConstraints - Type constraint system for Moose
a15dff8d 142
143=head1 SYNOPSIS
144
145 use Moose::Util::TypeConstraints;
146
147 type Num => where { Scalar::Util::looks_like_number($_) };
148
149 subtype Natural
150 => as Num
151 => where { $_ > 0 };
152
153 subtype NaturalLessThanTen
154 => as Natural
155 => where { $_ < 10 };
6b8bd8d3 156
157 coerce Num
d6e2d9a1 158 => from Str
159 => via { 0+$_ };
a15dff8d 160
161=head1 DESCRIPTION
162
e522431d 163This module provides Moose with the ability to create type contraints
164to be are used in both attribute definitions and for method argument
165validation.
166
167This is B<NOT> a type system for Perl 5.
168
e522431d 169This module also provides a simple hierarchy for Perl 5 types, this
170could probably use some work, but it works for me at the moment.
171
172 Any
173 Value
174 Int
175 Str
176 Ref
177 ScalarRef
178 ArrayRef
179 HashRef
180 CodeRef
181 RegexpRef
182 Object
183
184Suggestions for improvement are welcome.
185
a15dff8d 186=head1 FUNCTIONS
187
182134e8 188=head2 Type Constraint Registry
189
190=over 4
191
192=item B<find_type_constraint ($type_name)>
193
82168dbb 194=item B<create_type_constraint ($type_name, $type_constraint)>
182134e8 195
196=item B<find_type_coercion>
197
198=item B<register_type_coercion>
199
200=item B<export_type_contstraints_as_functions>
201
4b598ea3 202=item B<dump_type_constraints>
203
182134e8 204=back
205
a15dff8d 206=head2 Type Constraint Constructors
207
208=over 4
209
210=item B<type>
211
212=item B<subtype>
213
214=item B<as>
215
216=item B<where>
217
182134e8 218=item B<coerce>
219
d6e2d9a1 220=item B<from>
221
222=item B<via>
182134e8 223
a15dff8d 224=back
225
226=head2 Built-in Type Constraints
227
228=over 4
229
230=item B<Any>
231
232=item B<Value>
233
234=item B<Int>
235
236=item B<Str>
237
238=item B<Ref>
239
240=item B<ArrayRef>
241
242=item B<CodeRef>
243
244=item B<HashRef>
245
246=item B<RegexpRef>
247
248=item B<ScalarRef>
249
250=item B<Object>
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