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