actually, there's no reason that overriding 'is' is unsafe
[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
1aae641c 10use List::Util qw(first);
11
db236a63 12our $VERSION = '1.10';
75b95414 13$VERSION = eval $VERSION;
d44714be 14our $AUTHORITY = 'cpan:STEVAN';
8ee73eeb 15
d67145ed 16use base 'Moose::Meta::TypeConstraint';
17
8ee73eeb 18__PACKAGE__->meta->add_attribute('type_constraints' => (
19 accessor => 'type_constraints',
20 default => sub { [] }
21));
22
d03bd989 23sub new {
3726f905 24 my ($class, %options) = @_;
816ef2e2 25
26 my $name = join '|' => sort { $a cmp $b }
27 map { $_->name } @{ $options{type_constraints} };
28
3726f905 29 my $self = $class->SUPER::new(
816ef2e2 30 name => $name,
31 %options,
3726f905 32 );
816ef2e2 33
3726f905 34 $self->_set_constraint(sub { $self->check($_[0]) });
35 $self->coercion(Moose::Meta::TypeCoercion::Union->new(
36 type_constraint => $self
37 ));
8ee73eeb 38 return $self;
39}
40
816ef2e2 41sub _actually_compile_type_constraint {
42 my $self = shift;
43
44 my @constraints = @{ $self->type_constraints };
45
46 return sub {
47 my $value = shift;
48 foreach my $type (@constraints) {
49 return 1 if $type->check($value);
50 }
51 return undef;
52 };
53}
54
55
dabed765 56sub equals {
57 my ( $self, $type_or_name ) = @_;
58
59 my $other = Moose::Util::TypeConstraints::find_type_constraint($type_or_name);
60
61 return unless $other->isa(__PACKAGE__);
62
63 my @self_constraints = @{ $self->type_constraints };
64 my @other_constraints = @{ $other->type_constraints };
65
66 return unless @self_constraints == @other_constraints;
67
68 # FIXME presort type constraints for efficiency?
69 constraint: foreach my $constraint ( @self_constraints ) {
70 for ( my $i = 0; $i < @other_constraints; $i++ ) {
71 if ( $constraint->equals($other_constraints[$i]) ) {
72 splice @other_constraints, $i, 1;
73 next constraint;
74 }
75 }
76 }
77
78 return @other_constraints == 0;
79}
80
81sub parents {
82 my $self = shift;
83 $self->type_constraints;
84}
85
8ee73eeb 86sub validate {
3726f905 87 my ($self, $value) = @_;
8ee73eeb 88 my $message;
89 foreach my $type (@{$self->type_constraints}) {
90 my $err = $type->validate($value);
91 return unless defined $err;
92 $message .= ($message ? ' and ' : '') . $err
93 if defined $err;
94 }
d03bd989 95 return ($message . ' in (' . $self->name . ')') ;
8ee73eeb 96}
97
1aae641c 98sub find_type_for {
99 my ($self, $value) = @_;
100
101 return first { $_->check($value) } @{ $self->type_constraints };
102}
103
8ee73eeb 104sub is_a_type_of {
105 my ($self, $type_name) = @_;
106 foreach my $type (@{$self->type_constraints}) {
107 return 1 if $type->is_a_type_of($type_name);
108 }
d03bd989 109 return 0;
8ee73eeb 110}
111
112sub is_subtype_of {
113 my ($self, $type_name) = @_;
114 foreach my $type (@{$self->type_constraints}) {
115 return 1 if $type->is_subtype_of($type_name);
116 }
117 return 0;
118}
119
85a9908f 120sub create_child_type {
622c9332 121 my ( $self, %opts ) = @_;
122
123 my $constraint
124 = Moose::Meta::TypeConstraint->new( %opts, parent => $self );
125
9ceb576e 126 # if we have a type constraint union, and no
127 # type check, this means we are just aliasing
128 # the union constraint, which means we need to
129 # handle this differently.
130 # - SL
622c9332 131 if ( not( defined $opts{constraint} )
132 && $self->has_coercion ) {
133 $constraint->coercion(
134 Moose::Meta::TypeCoercion::Union->new(
135 type_constraint => $self,
136 )
137 );
9ceb576e 138 }
622c9332 139
9ceb576e 140 return $constraint;
141}
142
8ee73eeb 1431;
144
145__END__
146
147=pod
148
39b3bc94 149=head1 NAME
150
ecb59493 151Moose::Meta::TypeConstraint::Union - A union of Moose type constraints
39b3bc94 152
153=head1 DESCRIPTION
154
ae2f99ea 155This metaclass represents a union of type constraints. A union takes
156multiple type constraints, and is true if any one of its member
157constraints is true.
ecb59493 158
ae2f99ea 159=head1 INHERITANCE
ecb59493 160
ae2f99ea 161C<Moose::Meta::TypeConstraint::Union> is a subclass of
162L<Moose::Meta::TypeConstraint>.
ecb59493 163
39b3bc94 164=over 4
165
ae2f99ea 166=item B<< Moose::Meta::TypeConstraint::Union->new(%options) >>
39b3bc94 167
ae2f99ea 168This creates a new class type constraint based on the given
169C<%options>.
1b58cb9f 170
ae2f99ea 171It takes the same options as its parent. It also requires an
172additional option, C<type_constraints>. This is an array reference
173containing the L<Moose::Meta::TypeConstraint> objects that are the
174members of the union type. The C<name> option defaults to the names
175all of these member types sorted and then joined by a pipe (|).
dabed765 176
ae2f99ea 177The constructor sets the implementation of the constraint so that is
178simply calls C<check> on the newly created object.
ecb59493 179
ae2f99ea 180Finally, the constructor also makes sure that the object's C<coercion>
181attribute is a L<Moose::Meta::TypeCoercion::Union> object.
ecb59493 182
ae2f99ea 183=item B<< $constraint->type_constraints >>
ecb59493 184
ae2f99ea 185This returns the array reference of C<type_constraints> provided to
186the constructor.
39b3bc94 187
ae2f99ea 188=item B<< $constraint->parents >>
39b3bc94 189
ae2f99ea 190This returns the same constraint as the C<type_constraints> method.
39b3bc94 191
ae2f99ea 192=item B<< $constraint->check($value) >>
39b3bc94 193
ae2f99ea 194=item B<< $constraint->validate($value) >>
39b3bc94 195
ae2f99ea 196These two methods simply call the relevant method on each of the
197member type constraints in the union. If any type accepts the value,
198the value is valid.
39b3bc94 199
ae2f99ea 200With C<validate> the error message returned includes all of the error
201messages returned by the member type constraints.
39b3bc94 202
ae2f99ea 203=item B<< $constraint->equals($type_name_or_object) >>
39b3bc94 204
ae2f99ea 205A type is considered equal if it is also a union type, and the two
206unions have the same member types.
39b3bc94 207
1aae641c 208=item B<< $constraint->find_type_for($value) >>
209
210This returns the first member type constraint for which C<check($value)> is
211true, allowing you to determine which of the Union's member type constraints
212a given value matches.
213
ae2f99ea 214=item B<< $constraint->is_a_type_of($type_name_or_object) >>
ecb59493 215
ae2f99ea 216This returns true if any of the member type constraints return true
217for the C<is_a_type_of> method.
ecb59493 218
ae2f99ea 219=item B<< $constraint->is_subtype_of >>
39b3bc94 220
ae2f99ea 221This returns true if any of the member type constraints return true
222for the C<is_a_subtype_of> method.
0eec94be 223
ae2f99ea 224=item B<< $constraint->create_child_type(%options) >>
0eec94be 225
ae2f99ea 226This returns a new L<Moose::Meta::TypeConstraint> object with the type
227as its parent.
9ceb576e 228
39b3bc94 229=back
230
231=head1 BUGS
232
d4048ef3 233See L<Moose/BUGS> for details on reporting bugs.
39b3bc94 234
235=head1 AUTHOR
236
237Stevan Little E<lt>stevan@iinteractive.comE<gt>
238
39b3bc94 239=head1 COPYRIGHT AND LICENSE
240
7e0492d3 241Copyright 2006-2010 by Infinity Interactive, Inc.
39b3bc94 242
243L<http://www.iinteractive.com>
244
245This library is free software; you can redistribute it and/or modify
246it under the same terms as Perl itself.
247
8ee73eeb 248=cut