Add method decls in meta type constraint class.
[gitmo/Mouse.git] / lib / Mouse / Meta / TypeConstraint.pm
CommitLineData
684db121 1package Mouse::Meta::TypeConstraint;
bc69ee88 2use Mouse::Util qw(:meta); # enables strict and warnings
9c85e9dc 3
f5ee065f 4use overload
c489a477 5 'bool' => sub { 1 }, # always true
6
93540011 7 '""' => sub { $_[0]->name }, # stringify to tc name
8adc0b23 8
9 '|' => sub { # or-combination
10 require Mouse::Util::TypeConstraints;
11 return Mouse::Util::TypeConstraints::find_or_parse_type_constraint(
12 "$_[0] | $_[1]",
13 );
14 },
15
f5ee065f 16 fallback => 1;
684db121 17
ca352580 18use Carp ();
6d28c5cf 19
684db121 20sub new {
f5ee065f 21 my($class, %args) = @_;
22
23 $args{name} = '__ANON__' if !defined $args{name};
684db121 24
3b89ea91 25 my $check = delete $args{optimized};
26
3b89ea91 27 if($check){
28 $args{hand_optimized_type_constraint} = $check;
29 $args{compiled_type_constraint} = $check;
30 }
31
32 $check = $args{constraint};
f5ee065f 33
f5ee065f 34 if(defined($check) && ref($check) ne 'CODE'){
ca352580 35 Carp::confess("Constraint for $args{name} is not a CODE reference");
f5ee065f 36 }
37
3b89ea91 38 $args{package_defined_in} ||= caller;
39
f5ee065f 40 my $self = bless \%args, $class;
3b89ea91 41 $self->compile_type_constraint() if !$self->{hand_optimized_type_constraint};
f5ee065f 42
ffbbf459 43 if($self->{type_constraints}){ # Union
44 my @coercions;
45 foreach my $type(@{$self->{type_constraints}}){
46 if($type->has_coercion){
47 push @coercions, $type;
48 }
49 }
50 if(@coercions){
51 $self->{_compiled_type_coercion} = sub {
52 my($thing) = @_;
53 foreach my $type(@coercions){
54 my $value = $type->coerce($thing);
55 return $value if $self->check($value);
56 }
57 return $thing;
58 };
59 }
60 }
61
f5ee065f 62 return $self;
63}
64
65sub create_child_type{
66 my $self = shift;
e98220ab 67 # XXX: FIXME
68 return ref($self)->new(
3b89ea91 69 # a child inherits its parent's attributes
70 %{$self},
71
72 # but does not inherit 'compiled_type_constraint' and 'hand_optimized_type_constraint'
73 compiled_type_constraint => undef,
74 hand_optimized_type_constraint => undef,
75
76 # and is given child-specific args, of course.
77 @_,
78
79 # and its parent
80 parent => $self,
e98220ab 81 );
684db121 82}
83
4c99ea95 84sub name;
85sub parent;
86sub message;
87sub has_coercion;
88sub _compiled_type_constraint;
89sub _compiled_type_coercion;
90
91sub compile_type_constraint;
92
ffbbf459 93sub _add_type_coercions{
94 my $self = shift;
95
96 my $coercions = ($self->{_coercion_map} ||= []);
97 my %has = map{ $_->[0] => undef } @{$coercions};
98
99 for(my $i = 0; $i < @_; $i++){
100 my $from = $_[ $i];
101 my $action = $_[++$i];
102
103 if(exists $has{$from}){
ca352580 104 Carp::confess("A coercion action already exists for '$from'");
ffbbf459 105 }
106
107 my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from)
ca352580 108 or Carp::confess("Could not find the type constraint ($from) to coerce from");
ffbbf459 109
110 push @{$coercions}, [ $type => $action ];
111 }
112
113 # compile
114 if(exists $self->{type_constraints}){ # union type
ca352580 115 Carp::confess("Cannot add additional type coercions to Union types");
ffbbf459 116 }
117 else{
118 $self->{_compiled_type_coercion} = sub {
278448b8 119 my($thing) = @_;
120 foreach my $pair (@{$coercions}) {
121 #my ($constraint, $converter) = @$pair;
122 if ($pair->[0]->check($thing)) {
ffbbf459 123 local $_ = $thing;
124 return $pair->[1]->($thing);
278448b8 125 }
126 }
127 return $thing;
ffbbf459 128 };
129 }
130 return;
131}
132
feb0e21b 133sub check {
134 my $self = shift;
ffbbf459 135 return $self->_compiled_type_constraint->(@_);
136}
137
138sub coerce {
139 my $self = shift;
ffbbf459 140
141 return $_[0] if $self->_compiled_type_constraint->(@_);
142
93540011 143 my $coercion = $self->_compiled_type_coercion;
144 return $coercion ? $coercion->(@_) : $_[0];
feb0e21b 145}
146
147sub get_message {
148 my ($self, $value) = @_;
149 if ( my $msg = $self->message ) {
150 local $_ = $value;
151 return $msg->($value);
152 }
153 else {
154 $value = ( defined $value ? overload::StrVal($value) : 'undef' );
155 return "Validation failed for '$self' failed with value $value";
156 }
157}
158
159sub is_a_type_of{
160 my($self, $other) = @_;
161
162 # ->is_a_type_of('__ANON__') is always false
ca352580 163 return 0 if !ref($other) && $other eq '__ANON__';
feb0e21b 164
165 (my $other_name = $other) =~ s/\s+//g;
166
167 return 1 if $self->name eq $other_name;
168
169 if(exists $self->{type_constraints}){ # union
170 foreach my $type(@{$self->{type_constraints}}){
171 return 1 if $type->name eq $other_name;
172 }
173 }
174
175 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
176 return 1 if $parent->name eq $other_name;
177 }
178
179 return 0;
180}
181
b4d791ba 182# See also Moose::Meta::TypeConstraint::Parameterizable
183sub parameterize{
184 my($self, $param, $name) = @_;
185
186 if(!ref $param){
187 require Mouse::Util::TypeConstraints;
188 $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
189 }
190
191 $name ||= sprintf '%s[%s]', $self->name, $param->name;
192
193 my $generator = $self->{constraint_generator}
194 || Carp::confess("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
195
196 return Mouse::Meta::TypeConstraint->new(
5a363f78 197 name => $name,
198 parent => $self,
199 parameter => $param,
200 constraint => $generator->($param), # must be 'constraint', not 'optimized'
b4d791ba 201
5a363f78 202 type => 'Parameterized',
b4d791ba 203 );
204}
feb0e21b 205
684db121 2061;
207__END__
208
209=head1 NAME
210
1820fffe 211Mouse::Meta::TypeConstraint - The Mouse Type Constraint metaclass
684db121 212
a25ca8d6 213=head1 VERSION
214
01e830f7 215This document describes Mouse version 0.49
a25ca8d6 216
684db121 217=head1 DESCRIPTION
218
219For the most part, the only time you will ever encounter an
220instance of this class is if you are doing some serious deep
221introspection. This API should not be considered final, but
222it is B<highly unlikely> that this will matter to a regular
223Mouse user.
224
225Don't use this.
226
227=head1 METHODS
228
229=over 4
230
231=item B<new>
232
233=item B<name>
234
235=back
236
1820fffe 237=head1 SEE ALSO
238
239L<Moose::Meta::TypeConstraint>
240
684db121 241=cut
242