Apply a patch contributed by chocolateboy (RT #54383) to allow "use Mouse::Tiny VERSION"
[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
ffbbf459 84sub _add_type_coercions{
85 my $self = shift;
86
87 my $coercions = ($self->{_coercion_map} ||= []);
88 my %has = map{ $_->[0] => undef } @{$coercions};
89
90 for(my $i = 0; $i < @_; $i++){
91 my $from = $_[ $i];
92 my $action = $_[++$i];
93
94 if(exists $has{$from}){
ca352580 95 Carp::confess("A coercion action already exists for '$from'");
ffbbf459 96 }
97
98 my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from)
ca352580 99 or Carp::confess("Could not find the type constraint ($from) to coerce from");
ffbbf459 100
101 push @{$coercions}, [ $type => $action ];
102 }
103
104 # compile
105 if(exists $self->{type_constraints}){ # union type
ca352580 106 Carp::confess("Cannot add additional type coercions to Union types");
ffbbf459 107 }
108 else{
109 $self->{_compiled_type_coercion} = sub {
278448b8 110 my($thing) = @_;
111 foreach my $pair (@{$coercions}) {
112 #my ($constraint, $converter) = @$pair;
113 if ($pair->[0]->check($thing)) {
ffbbf459 114 local $_ = $thing;
115 return $pair->[1]->($thing);
278448b8 116 }
117 }
118 return $thing;
ffbbf459 119 };
120 }
121 return;
122}
123
feb0e21b 124sub check {
125 my $self = shift;
ffbbf459 126 return $self->_compiled_type_constraint->(@_);
127}
128
129sub coerce {
130 my $self = shift;
ffbbf459 131
132 return $_[0] if $self->_compiled_type_constraint->(@_);
133
93540011 134 my $coercion = $self->_compiled_type_coercion;
135 return $coercion ? $coercion->(@_) : $_[0];
feb0e21b 136}
137
138sub get_message {
139 my ($self, $value) = @_;
140 if ( my $msg = $self->message ) {
141 local $_ = $value;
142 return $msg->($value);
143 }
144 else {
145 $value = ( defined $value ? overload::StrVal($value) : 'undef' );
146 return "Validation failed for '$self' failed with value $value";
147 }
148}
149
150sub is_a_type_of{
151 my($self, $other) = @_;
152
153 # ->is_a_type_of('__ANON__') is always false
ca352580 154 return 0 if !ref($other) && $other eq '__ANON__';
feb0e21b 155
156 (my $other_name = $other) =~ s/\s+//g;
157
158 return 1 if $self->name eq $other_name;
159
160 if(exists $self->{type_constraints}){ # union
161 foreach my $type(@{$self->{type_constraints}}){
162 return 1 if $type->name eq $other_name;
163 }
164 }
165
166 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
167 return 1 if $parent->name eq $other_name;
168 }
169
170 return 0;
171}
172
b4d791ba 173# See also Moose::Meta::TypeConstraint::Parameterizable
174sub parameterize{
175 my($self, $param, $name) = @_;
176
177 if(!ref $param){
178 require Mouse::Util::TypeConstraints;
179 $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
180 }
181
182 $name ||= sprintf '%s[%s]', $self->name, $param->name;
183
184 my $generator = $self->{constraint_generator}
185 || Carp::confess("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
186
187 return Mouse::Meta::TypeConstraint->new(
5a363f78 188 name => $name,
189 parent => $self,
190 parameter => $param,
191 constraint => $generator->($param), # must be 'constraint', not 'optimized'
b4d791ba 192
5a363f78 193 type => 'Parameterized',
b4d791ba 194 );
195}
feb0e21b 196
684db121 1971;
198__END__
199
200=head1 NAME
201
1820fffe 202Mouse::Meta::TypeConstraint - The Mouse Type Constraint metaclass
684db121 203
a25ca8d6 204=head1 VERSION
205
01e830f7 206This document describes Mouse version 0.49
a25ca8d6 207
684db121 208=head1 DESCRIPTION
209
210For the most part, the only time you will ever encounter an
211instance of this class is if you are doing some serious deep
212introspection. This API should not be considered final, but
213it is B<highly unlikely> that this will matter to a regular
214Mouse user.
215
216Don't use this.
217
218=head1 METHODS
219
220=over 4
221
222=item B<new>
223
224=item B<name>
225
226=back
227
1820fffe 228=head1 SEE ALSO
229
230L<Moose::Meta::TypeConstraint>
231
684db121 232=cut
233