162b80a6e4c9d0b8375622216625a89dded304a8
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint / Union.pm
1
2 package Moose::Meta::TypeConstraint::Union;
3
4 use strict;
5 use warnings;
6 use metaclass;
7
8 our $VERSION   = '0.04';
9 our $AUTHORITY = 'cpan:STEVAN';
10
11 __PACKAGE__->meta->add_attribute('type_constraints' => (
12     accessor  => 'type_constraints',
13     default   => sub { [] }
14 ));
15
16 sub new { 
17     my $class = shift;
18     my $self  = $class->meta->new_object(@_);
19     return $self;
20 }
21
22 sub name { join ' | ' => map { $_->name } @{$_[0]->type_constraints} }
23
24 # NOTE:
25 # this should probably never be used
26 # but we include it here for completeness
27 sub constraint    { 
28     my $self = shift;
29     sub { $self->check($_[0]) }; 
30 }
31
32 # conform to the TypeConstraint API
33 sub parent        { undef  }
34 sub message       { undef  }
35 sub has_message   { 0      }
36
37 # FIXME:
38 # not sure what this should actually do here
39 sub coercion { undef  }
40
41 # this should probably be memoized
42 sub has_coercion  {
43     my $self  = shift;
44     foreach my $type (@{$self->type_constraints}) {
45         return 1 if $type->has_coercion
46     }
47     return 0;    
48 }
49
50 # NOTE:
51 # this feels too simple, and may not always DWIM
52 # correctly, especially in the presence of 
53 # close subtype relationships, however it should 
54 # work for a fair percentage of the use cases
55 sub coerce { 
56     my $self  = shift;
57     my $value = shift;
58     foreach my $type (@{$self->type_constraints}) {
59         if ($type->has_coercion) {
60             my $temp = $type->coerce($value);
61             return $temp if $self->check($temp);
62         }
63     }
64     return undef;    
65 }
66
67 sub _compiled_type_constraint {
68     my $self  = shift;
69     return sub {
70         my $value = shift;
71         foreach my $type (@{$self->type_constraints}) {
72             return 1 if $type->check($value);
73         }
74         return undef;    
75     }
76 }
77
78 sub check {
79     my $self  = shift;
80     my $value = shift;
81     $self->_compiled_type_constraint->($value);
82 }
83
84 sub validate {
85     my $self  = shift;
86     my $value = shift;
87     my $message;
88     foreach my $type (@{$self->type_constraints}) {
89         my $err = $type->validate($value);
90         return unless defined $err;
91         $message .= ($message ? ' and ' : '') . $err
92             if defined $err;
93     }
94     return ($message . ' in (' . $self->name . ')') ;    
95 }
96
97 sub is_a_type_of {
98     my ($self, $type_name) = @_;
99     foreach my $type (@{$self->type_constraints}) {
100         return 1 if $type->is_a_type_of($type_name);
101     }
102     return 0;    
103 }
104
105 sub is_subtype_of {
106     my ($self, $type_name) = @_;
107     foreach my $type (@{$self->type_constraints}) {
108         return 1 if $type->is_subtype_of($type_name);
109     }
110     return 0;
111 }
112
113 1;
114
115 __END__
116
117 =pod
118
119 =head1 NAME
120
121 Moose::Meta::TypeConstraint::Union - A union of Moose type constraints
122
123 =head1 DESCRIPTION
124
125 This metaclass represents a union of Moose type constraints. More 
126 details to be explained later (possibly in a Cookbook::Recipe).
127
128 This actually used to be part of Moose::Meta::TypeConstraint, but it 
129 is now better off in it's own file. 
130
131 =head1 METHODS
132
133 This class is not a subclass of Moose::Meta::TypeConstraint, 
134 but it does provide the same API
135
136 =over 4
137
138 =item B<meta>
139
140 =item B<new>
141
142 =item B<name>
143
144 =item B<type_constraints>
145
146 =item B<constraint>
147
148 =back
149
150 =head2 Overriden methods 
151
152 =over 4
153
154 =item B<check>
155
156 =item B<coerce>
157
158 =item B<validate>
159
160 =item B<is_a_type_of>
161
162 =item B<is_subtype_of>
163
164 =back
165
166 =head2 Empty or Stub methods
167
168 These methods tend to not be very relevant in 
169 the context of a union. Either that or they are 
170 just difficult to specify and not very useful 
171 anyway. They are here for completeness.
172
173 =over 4
174
175 =item B<parent>
176
177 =item B<coercion>
178
179 =item B<has_coercion>
180
181 =item B<message>
182
183 =item B<has_message>
184
185 =back
186
187 =head1 BUGS
188
189 All complex software has bugs lurking in it, and this module is no 
190 exception. If you find a bug please either email me, or add the bug
191 to cpan-RT.
192
193 =head1 AUTHOR
194
195 Stevan Little E<lt>stevan@iinteractive.comE<gt>
196
197 =head1 COPYRIGHT AND LICENSE
198
199 Copyright 2006, 2007 by Infinity Interactive, Inc.
200
201 L<http://www.iinteractive.com>
202
203 This library is free software; you can redistribute it and/or modify
204 it under the same terms as Perl itself.
205
206 =cut