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