Small refactoring of Union type to remove some wacky code
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint / Union.pm
CommitLineData
8ee73eeb 1
2package Moose::Meta::TypeConstraint::Union;
3
4use strict;
5use warnings;
6use metaclass;
7
3726f905 8use Moose::Meta::TypeCoercion::Union;
9
4b2189ce 10our $VERSION = '0.72';
75b95414 11$VERSION = eval $VERSION;
d44714be 12our $AUTHORITY = 'cpan:STEVAN';
8ee73eeb 13
d67145ed 14use base 'Moose::Meta::TypeConstraint';
15
8ee73eeb 16__PACKAGE__->meta->add_attribute('type_constraints' => (
17 accessor => 'type_constraints',
18 default => sub { [] }
19));
20
21sub new {
3726f905 22 my ($class, %options) = @_;
816ef2e2 23
24 my $name = join '|' => sort { $a cmp $b }
25 map { $_->name } @{ $options{type_constraints} };
26
3726f905 27 my $self = $class->SUPER::new(
816ef2e2 28 name => $name,
29 %options,
3726f905 30 );
816ef2e2 31
3726f905 32 $self->_set_constraint(sub { $self->check($_[0]) });
33 $self->coercion(Moose::Meta::TypeCoercion::Union->new(
34 type_constraint => $self
35 ));
8ee73eeb 36 return $self;
37}
38
816ef2e2 39sub _actually_compile_type_constraint {
40 my $self = shift;
41
42 my @constraints = @{ $self->type_constraints };
43
44 return sub {
45 my $value = shift;
46 foreach my $type (@constraints) {
47 return 1 if $type->check($value);
48 }
49 return undef;
50 };
51}
52
53
dabed765 54sub equals {
55 my ( $self, $type_or_name ) = @_;
56
57 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
58
59 return unless $other->isa(__PACKAGE__);
60
61 my @self_constraints = @{ $self->type_constraints };
62 my @other_constraints = @{ $other->type_constraints };
63
64 return unless @self_constraints == @other_constraints;
65
66 # FIXME presort type constraints for efficiency?
67 constraint: foreach my $constraint ( @self_constraints ) {
68 for ( my $i = 0; $i < @other_constraints; $i++ ) {
69 if ( $constraint->equals($other_constraints[$i]) ) {
70 splice @other_constraints, $i, 1;
71 next constraint;
72 }
73 }
74 }
75
76 return @other_constraints == 0;
77}
78
79sub parents {
80 my $self = shift;
81 $self->type_constraints;
82}
83
8ee73eeb 84sub validate {
3726f905 85 my ($self, $value) = @_;
8ee73eeb 86 my $message;
87 foreach my $type (@{$self->type_constraints}) {
88 my $err = $type->validate($value);
89 return unless defined $err;
90 $message .= ($message ? ' and ' : '') . $err
91 if defined $err;
92 }
93 return ($message . ' in (' . $self->name . ')') ;
94}
95
96sub is_a_type_of {
97 my ($self, $type_name) = @_;
98 foreach my $type (@{$self->type_constraints}) {
99 return 1 if $type->is_a_type_of($type_name);
100 }
101 return 0;
102}
103
104sub is_subtype_of {
105 my ($self, $type_name) = @_;
106 foreach my $type (@{$self->type_constraints}) {
107 return 1 if $type->is_subtype_of($type_name);
108 }
109 return 0;
110}
111
85a9908f 112sub create_child_type {
622c9332 113 my ( $self, %opts ) = @_;
114
115 my $constraint
116 = Moose::Meta::TypeConstraint->new( %opts, parent => $self );
117
9ceb576e 118 # if we have a type constraint union, and no
119 # type check, this means we are just aliasing
120 # the union constraint, which means we need to
121 # handle this differently.
122 # - SL
622c9332 123 if ( not( defined $opts{constraint} )
124 && $self->has_coercion ) {
125 $constraint->coercion(
126 Moose::Meta::TypeCoercion::Union->new(
127 type_constraint => $self,
128 )
129 );
9ceb576e 130 }
622c9332 131
9ceb576e 132 return $constraint;
133}
134
8ee73eeb 1351;
136
137__END__
138
139=pod
140
39b3bc94 141=head1 NAME
142
ecb59493 143Moose::Meta::TypeConstraint::Union - A union of Moose type constraints
39b3bc94 144
145=head1 DESCRIPTION
146
ecb59493 147This metaclass represents a union of Moose type constraints. More
5cfe3805 148details to be explained later (possibly in a Cookbook recipe).
ecb59493 149
150This actually used to be part of Moose::Meta::TypeConstraint, but it
151is now better off in it's own file.
152
39b3bc94 153=head1 METHODS
154
ecb59493 155This class is not a subclass of Moose::Meta::TypeConstraint,
156but it does provide the same API
157
39b3bc94 158=over 4
159
ecb59493 160=item B<meta>
39b3bc94 161
ecb59493 162=item B<new>
39b3bc94 163
ecb59493 164=item B<name>
165
166=item B<type_constraints>
39b3bc94 167
dabed765 168=item B<parents>
169
39b3bc94 170=item B<constraint>
171
1b58cb9f 172=item B<includes_type>
173
dabed765 174=item B<equals>
175
ecb59493 176=back
39b3bc94 177
6549b0d1 178=head2 Overridden methods
ecb59493 179
180=over 4
181
182=item B<check>
183
184=item B<coerce>
185
186=item B<validate>
39b3bc94 187
188=item B<is_a_type_of>
189
190=item B<is_subtype_of>
191
ecb59493 192=back
39b3bc94 193
ecb59493 194=head2 Empty or Stub methods
39b3bc94 195
ecb59493 196These methods tend to not be very relevant in
197the context of a union. Either that or they are
198just difficult to specify and not very useful
199anyway. They are here for completeness.
39b3bc94 200
ecb59493 201=over 4
39b3bc94 202
203=item B<parent>
204
ecb59493 205=item B<coercion>
39b3bc94 206
ecb59493 207=item B<has_coercion>
208
209=item B<message>
210
211=item B<has_message>
39b3bc94 212
0eec94be 213=item B<hand_optimized_type_constraint>
214
215=item B<has_hand_optimized_type_constraint>
216
85a9908f 217=item B<create_child_type>
9ceb576e 218
39b3bc94 219=back
220
221=head1 BUGS
222
223All complex software has bugs lurking in it, and this module is no
224exception. If you find a bug please either email me, or add the bug
225to cpan-RT.
226
227=head1 AUTHOR
228
229Stevan Little E<lt>stevan@iinteractive.comE<gt>
230
39b3bc94 231=head1 COPYRIGHT AND LICENSE
232
2840a3b2 233Copyright 2006-2009 by Infinity Interactive, Inc.
39b3bc94 234
235L<http://www.iinteractive.com>
236
237This library is free software; you can redistribute it and/or modify
238it under the same terms as Perl itself.
239
8ee73eeb 240=cut