moving things around to get ready to support Class::MOP 0.36
[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.03';
9
10 __PACKAGE__->meta->add_attribute('type_constraints' => (
11     accessor  => 'type_constraints',
12     default   => sub { [] }
13 ));
14
15 sub new { 
16     my $class = shift;
17     my $self  = $class->meta->new_object(@_);
18     return $self;
19 }
20
21 sub name { join ' | ' => map { $_->name } @{$_[0]->type_constraints} }
22
23 # NOTE:
24 # this should probably never be used
25 # but we include it here for completeness
26 sub constraint    { 
27     my $self = shift;
28     sub { $self->check($_[0]) }; 
29 }
30
31 # conform to the TypeConstraint API
32 sub parent        { undef  }
33 sub message       { undef  }
34 sub has_message   { 0      }
35
36 # FIXME:
37 # not sure what this should actually do here
38 sub coercion { undef  }
39
40 # this should probably be memoized
41 sub has_coercion  {
42     my $self  = shift;
43     foreach my $type (@{$self->type_constraints}) {
44         return 1 if $type->has_coercion
45     }
46     return 0;    
47 }
48
49 # NOTE:
50 # this feels too simple, and may not always DWIM
51 # correctly, especially in the presence of 
52 # close subtype relationships, however it should 
53 # work for a fair percentage of the use cases
54 sub coerce { 
55     my $self  = shift;
56     my $value = shift;
57     foreach my $type (@{$self->type_constraints}) {
58         if ($type->has_coercion) {
59             my $temp = $type->coerce($value);
60             return $temp if $self->check($temp);
61         }
62     }
63     return undef;    
64 }
65
66 sub _compiled_type_constraint {
67     my $self  = shift;
68     return sub {
69         my $value = shift;
70         foreach my $type (@{$self->type_constraints}) {
71             return 1 if $type->check($value);
72         }
73         return undef;    
74     }
75 }
76
77 sub check {
78     my $self  = shift;
79     my $value = shift;
80     $self->_compiled_type_constraint->($value);
81 }
82
83 sub validate {
84     my $self  = shift;
85     my $value = shift;
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
96 sub 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
104 sub 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
112 1;
113
114 __END__
115
116 =pod
117
118 =cut