Fix XS for RegexpRef
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints / Builtins.pm
CommitLineData
06d02aac 1package Moose::Util::TypeConstraints::Builtins;
2
3use strict;
4use warnings;
5
9882ca98 6use Scalar::Util qw( blessed looks_like_number reftype );
06d02aac 7
8sub type { goto &Moose::Util::TypeConstraints::type }
9sub subtype { goto &Moose::Util::TypeConstraints::subtype }
10sub as { goto &Moose::Util::TypeConstraints::as }
11sub where (&) { goto &Moose::Util::TypeConstraints::where }
12sub optimize_as (&) { goto &Moose::Util::TypeConstraints::optimize_as }
13
14sub 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 178sub _Value { defined($_[0]) && !ref($_[0]) }
179
180sub _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)).
184sub _Str {
185 defined($_[0])
186 && ( ref(\ $_[0] ) eq 'SCALAR'
187 || ref(\(my $value = $_[0])) eq 'SCALAR')
188}
189
190sub _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)
194sub _Int {
195 my $value = $_[0];
196 defined($value) && !ref($value) && $value =~ /\A-?[0-9]+\z/
197}
198
199sub _ScalarRef { ref($_[0]) eq 'SCALAR' || ref($_[0]) eq 'REF' }
200sub _ArrayRef { ref($_[0]) eq 'ARRAY' }
201sub _HashRef { ref($_[0]) eq 'HASH' }
202sub _CodeRef { ref($_[0]) eq 'CODE' }
203sub _GlobRef { ref($_[0]) eq 'GLOB' }
204
205# RegexpRef is implemented in Moose.xs
206
207sub _FileHandle {
208 ref( $_[0] ) eq 'GLOB' && Scalar::Util::openhandle( $_[0] )
209 or blessed( $_[0] ) && $_[0]->isa("IO::Handle");
210}
211
212sub _Object { blessed($_[0]) }
213
214sub _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
223sub _ClassName {
224 return Class::MOP::is_class_loaded( $_[0] );
225}
226
227sub _RoleName {
228 ClassName( $_[0] )
229 && ( Class::MOP::class_of( $_[0] ) || return )
230 ->isa('Moose::Meta::Role');
231}
232
06d02aac 2331;