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