Commit | Line | Data |
06d02aac |
1 | package Moose::Util::TypeConstraints::Builtins; |
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
9882ca98 |
6 | use Scalar::Util qw( blessed looks_like_number reftype ); |
06d02aac |
7 | |
8 | sub type { goto &Moose::Util::TypeConstraints::type } |
9 | sub subtype { goto &Moose::Util::TypeConstraints::subtype } |
10 | sub as { goto &Moose::Util::TypeConstraints::as } |
11 | sub where (&) { goto &Moose::Util::TypeConstraints::where } |
12 | sub optimize_as (&) { goto &Moose::Util::TypeConstraints::optimize_as } |
4e36cf24 |
13 | sub inline_as (&) { goto &Moose::Util::TypeConstraints::inline_as } |
06d02aac |
14 | |
15 | sub define_builtins { |
16 | my $registry = shift; |
17 | |
4e36cf24 |
18 | type 'Any' # meta-type including all |
19 | => where {1} |
20 | => inline_as { '1' }; |
06d02aac |
21 | |
4e36cf24 |
22 | subtype 'Item' # base-type |
94ab1609 |
23 | => as 'Any' |
24 | => inline_as { '1' }; |
4e36cf24 |
25 | |
26 | subtype 'Undef' |
27 | => as 'Item' |
28 | => where { !defined($_) } |
29 | => inline_as { "! defined $_[0]" }; |
30 | |
31 | subtype 'Defined' |
32 | => as 'Item' |
33 | => where { defined($_) } |
34 | => inline_as { "defined $_[0]" }; |
06d02aac |
35 | |
36 | subtype 'Bool' |
37 | => as 'Item' |
4e36cf24 |
38 | => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' } |
39 | => inline_as { qq{!defined($_[0]) || $_[0] eq "" || "$_[0]" eq '1' || "$_[0]" eq '0'} }; |
06d02aac |
40 | |
41 | subtype 'Value' |
42 | => as 'Defined' |
43 | => where { !ref($_) } |
4e36cf24 |
44 | => optimize_as( \&_Value ) |
45 | => inline_as { "defined $_[0] && ! ref $_[0]" }; |
06d02aac |
46 | |
47 | subtype 'Ref' |
48 | => as 'Defined' |
49 | => where { ref($_) } |
4e36cf24 |
50 | => optimize_as( \&_Ref ) |
51 | => inline_as { "ref $_[0]" }; |
06d02aac |
52 | |
53 | subtype 'Str' |
54 | => as 'Value' |
55 | => where { ref(\$_) eq 'SCALAR' } |
4e36cf24 |
56 | => optimize_as( \&_Str ) |
57 | => inline_as { |
58 | return ( qq{defined $_[0]} |
59 | . qq{&& ( ref(\\ $_[0] ) eq 'SCALAR'} |
60 | . qq{ || ref(\\(my \$value = $_[0])) eq 'SCALAR')} ); |
61 | }; |
06d02aac |
62 | |
63 | subtype 'Num' |
64 | => as 'Str' |
65 | => where { Scalar::Util::looks_like_number($_) } |
4e36cf24 |
66 | => optimize_as( \&_Num ) |
67 | => inline_as { "!ref $_[0] && Scalar::Util::looks_like_number($_[0])" }; |
06d02aac |
68 | |
69 | subtype 'Int' |
70 | => as 'Num' |
71 | => where { "$_" =~ /^-?[0-9]+$/ } |
4e36cf24 |
72 | => optimize_as( \&_Int ) |
73 | => inline_as { |
74 | return ( qq{defined $_[0]} |
75 | . qq{&& ! ref $_[0]} |
76 | . qq{&& ( my \$value = $_[0] ) =~ /\\A-?[0-9]+\\z/} ); |
77 | }; |
06d02aac |
78 | |
79 | subtype 'CodeRef' |
80 | => as 'Ref' |
81 | => where { ref($_) eq 'CODE' } |
4e36cf24 |
82 | => optimize_as( \&_CodeRef ) |
94ab1609 |
83 | => inline_as { qq{ref $_[0] eq 'CODE'} }; |
06d02aac |
84 | |
85 | subtype 'RegexpRef' |
86 | => as 'Ref' |
9882ca98 |
87 | => where( \&_RegexpRef ) |
4e36cf24 |
88 | => optimize_as( \&_RegexpRef ) |
94ab1609 |
89 | => inline_as { "Moose::Util::TypeConstraints::Builtins::_RegexpRef( $_[0] )" }; |
06d02aac |
90 | |
91 | subtype 'GlobRef' |
92 | => as 'Ref' |
93 | => where { ref($_) eq 'GLOB' } |
4e36cf24 |
94 | => optimize_as( \&_GlobRef ) |
94ab1609 |
95 | => inline_as { qq{ref $_[0] eq 'GLOB'} }; |
06d02aac |
96 | |
97 | # NOTE: scalar filehandles are GLOB refs, but a GLOB ref is not always a |
98 | # filehandle |
99 | subtype 'FileHandle' |
94ab1609 |
100 | => as 'Ref' |
06d02aac |
101 | => where { |
102 | Scalar::Util::openhandle($_) || ( blessed($_) && $_->isa("IO::Handle") ); |
103 | } |
4e36cf24 |
104 | => optimize_as( \&_FileHandle ) |
105 | => inline_as { |
94ab1609 |
106 | return ( qq{ref $_[0] eq 'GLOB'} |
4e36cf24 |
107 | . qq{&& Scalar::Util::openhandle( $_[0] )} |
94ab1609 |
108 | . qq{or Scalar::Util::blessed( $_[0] ) && $_[0]->isa("IO::Handle")} ); |
4e36cf24 |
109 | }; |
06d02aac |
110 | |
111 | subtype 'Object' |
112 | => as 'Ref' |
113 | => where { blessed($_) } |
4e36cf24 |
114 | => optimize_as( \&_Object ) |
115 | => inline_as { "Scalar::Util::blessed( $_[0] )" }; |
06d02aac |
116 | |
117 | # This type is deprecated. |
118 | subtype 'Role' |
119 | => as 'Object' |
120 | => where { $_->can('does') } |
4e36cf24 |
121 | => optimize_as( \&_Role ); |
06d02aac |
122 | |
123 | subtype 'ClassName' |
124 | => as 'Str' |
125 | => where { Class::MOP::is_class_loaded($_) } |
4e36cf24 |
126 | => optimize_as( \&_ClassName ) |
127 | => inline_as { "Class::MOP::is_class_loaded( $_[0] )" }; |
06d02aac |
128 | |
129 | subtype 'RoleName' |
130 | => as 'ClassName' |
131 | => where { |
132 | (Class::MOP::class_of($_) || return)->isa('Moose::Meta::Role'); |
133 | } |
4e36cf24 |
134 | => optimize_as( \&_RoleName ) |
135 | => inline_as { |
136 | return ( qq{Class::MOP::is_class_loaded( $_[0] )} |
137 | . qq{&& ( Class::MOP::class_of( $_[0] ) || return )} |
138 | . qq{ ->isa('Moose::Meta::Role')} ); |
139 | }; |
06d02aac |
140 | |
141 | $registry->add_type_constraint( |
142 | Moose::Meta::TypeConstraint::Parameterizable->new( |
143 | name => 'ScalarRef', |
144 | package_defined_in => __PACKAGE__, |
145 | parent => |
146 | Moose::Util::TypeConstraints::find_type_constraint('Ref'), |
147 | constraint => sub { ref($_) eq 'SCALAR' || ref($_) eq 'REF' }, |
9882ca98 |
148 | optimized => \&_ScalarRef, |
06d02aac |
149 | constraint_generator => sub { |
150 | my $type_parameter = shift; |
151 | my $check = $type_parameter->_compiled_type_constraint; |
152 | return sub { |
153 | return $check->( ${$_} ); |
154 | }; |
155 | } |
156 | ) |
157 | ); |
158 | |
159 | $registry->add_type_constraint( |
160 | Moose::Meta::TypeConstraint::Parameterizable->new( |
161 | name => 'ArrayRef', |
162 | package_defined_in => __PACKAGE__, |
163 | parent => |
164 | Moose::Util::TypeConstraints::find_type_constraint('Ref'), |
165 | constraint => sub { ref($_) eq 'ARRAY' }, |
9882ca98 |
166 | optimized => \&_ArrayRef, |
06d02aac |
167 | constraint_generator => sub { |
168 | my $type_parameter = shift; |
169 | my $check = $type_parameter->_compiled_type_constraint; |
170 | return sub { |
171 | foreach my $x (@$_) { |
172 | ( $check->($x) ) || return; |
173 | } |
174 | 1; |
175 | } |
176 | } |
177 | ) |
178 | ); |
179 | |
180 | $registry->add_type_constraint( |
181 | Moose::Meta::TypeConstraint::Parameterizable->new( |
182 | name => 'HashRef', |
183 | package_defined_in => __PACKAGE__, |
184 | parent => |
185 | Moose::Util::TypeConstraints::find_type_constraint('Ref'), |
186 | constraint => sub { ref($_) eq 'HASH' }, |
9882ca98 |
187 | optimized => \&_HashRef, |
06d02aac |
188 | constraint_generator => sub { |
189 | my $type_parameter = shift; |
190 | my $check = $type_parameter->_compiled_type_constraint; |
191 | return sub { |
192 | foreach my $x ( values %$_ ) { |
193 | ( $check->($x) ) || return; |
194 | } |
195 | 1; |
196 | } |
197 | } |
198 | ) |
199 | ); |
200 | |
201 | $registry->add_type_constraint( |
202 | Moose::Meta::TypeConstraint::Parameterizable->new( |
203 | name => 'Maybe', |
204 | package_defined_in => __PACKAGE__, |
205 | parent => |
206 | Moose::Util::TypeConstraints::find_type_constraint('Item'), |
207 | constraint => sub {1}, |
208 | constraint_generator => sub { |
209 | my $type_parameter = shift; |
210 | my $check = $type_parameter->_compiled_type_constraint; |
211 | return sub { |
212 | return 1 if not( defined($_) ) || $check->($_); |
213 | return; |
214 | } |
215 | } |
216 | ) |
217 | ); |
218 | } |
219 | |
9882ca98 |
220 | sub _Value { defined($_[0]) && !ref($_[0]) } |
221 | |
222 | sub _Ref { ref($_[0]) } |
223 | |
224 | # We might need to use a temporary here to flatten LVALUEs, for instance as in |
225 | # Str(substr($_,0,255)). |
226 | sub _Str { |
227 | defined($_[0]) |
228 | && ( ref(\ $_[0] ) eq 'SCALAR' |
229 | || ref(\(my $value = $_[0])) eq 'SCALAR') |
230 | } |
231 | |
232 | sub _Num { !ref($_[0]) && looks_like_number($_[0]) } |
233 | |
234 | # using a temporary here because regex matching promotes an IV to a PV, |
235 | # and that confuses some things (like JSON.pm) |
236 | sub _Int { |
237 | my $value = $_[0]; |
238 | defined($value) && !ref($value) && $value =~ /\A-?[0-9]+\z/ |
239 | } |
240 | |
241 | sub _ScalarRef { ref($_[0]) eq 'SCALAR' || ref($_[0]) eq 'REF' } |
242 | sub _ArrayRef { ref($_[0]) eq 'ARRAY' } |
243 | sub _HashRef { ref($_[0]) eq 'HASH' } |
244 | sub _CodeRef { ref($_[0]) eq 'CODE' } |
245 | sub _GlobRef { ref($_[0]) eq 'GLOB' } |
246 | |
247 | # RegexpRef is implemented in Moose.xs |
248 | |
249 | sub _FileHandle { |
250 | ref( $_[0] ) eq 'GLOB' && Scalar::Util::openhandle( $_[0] ) |
251 | or blessed( $_[0] ) && $_[0]->isa("IO::Handle"); |
252 | } |
253 | |
254 | sub _Object { blessed($_[0]) } |
255 | |
256 | sub _Role { |
257 | Moose::Deprecated::deprecated( |
258 | feature => 'Role type', |
259 | message => |
260 | 'The Role type has been deprecated. Maybe you meant to create a RoleName type? This type be will be removed in Moose 2.0200.' |
261 | ); |
262 | blessed( $_[0] ) && $_[0]->can('does'); |
263 | } |
264 | |
265 | sub _ClassName { |
266 | return Class::MOP::is_class_loaded( $_[0] ); |
267 | } |
268 | |
269 | sub _RoleName { |
4e36cf24 |
270 | _ClassName( $_[0] ) |
9882ca98 |
271 | && ( Class::MOP::class_of( $_[0] ) || return ) |
272 | ->isa('Moose::Meta::Role'); |
273 | } |
274 | |
06d02aac |
275 | 1; |