summaryrefslogtreecommitdiff
path: root/lib/Moose/Util/TypeConstraints/Builtins.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Moose/Util/TypeConstraints/Builtins.pm')
-rw-r--r--lib/Moose/Util/TypeConstraints/Builtins.pm305
1 files changed, 305 insertions, 0 deletions
diff --git a/lib/Moose/Util/TypeConstraints/Builtins.pm b/lib/Moose/Util/TypeConstraints/Builtins.pm
new file mode 100644
index 0000000..400afe6
--- /dev/null
+++ b/lib/Moose/Util/TypeConstraints/Builtins.pm
@@ -0,0 +1,305 @@
+package Moose::Util::TypeConstraints::Builtins;
+our $VERSION = '2.1405';
+
+use strict;
+use warnings;
+
+use Class::Load qw( is_class_loaded );
+use List::Util 1.33 ();
+use Scalar::Util qw( blessed );
+
+sub type { goto &Moose::Util::TypeConstraints::type }
+sub subtype { goto &Moose::Util::TypeConstraints::subtype }
+sub as { goto &Moose::Util::TypeConstraints::as }
+sub where (&) { goto &Moose::Util::TypeConstraints::where }
+sub inline_as (&) { goto &Moose::Util::TypeConstraints::inline_as }
+
+sub define_builtins {
+ my $registry = shift;
+
+ type 'Any' # meta-type including all
+ => where {1}
+ => inline_as { '1' };
+
+ subtype 'Item' # base type
+ => as 'Any'
+ => inline_as { '1' };
+
+ subtype 'Undef'
+ => as 'Item'
+ => where { !defined($_) }
+ => inline_as {
+ '!defined(' . $_[1] . ')'
+ };
+
+ subtype 'Defined'
+ => as 'Item'
+ => where { defined($_) }
+ => inline_as {
+ 'defined(' . $_[1] . ')'
+ };
+
+ subtype 'Bool'
+ => as 'Item'
+ => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' }
+ => inline_as {
+ '('
+ . '!defined(' . $_[1] . ') '
+ . '|| ' . $_[1] . ' eq "" '
+ . '|| (' . $_[1] . '."") eq "1" '
+ . '|| (' . $_[1] . '."") eq "0"'
+ . ')'
+ };
+
+ subtype 'Value'
+ => as 'Defined'
+ => where { !ref($_) }
+ => inline_as {
+ $_[0]->parent()->_inline_check($_[1])
+ . ' && !ref(' . $_[1] . ')'
+ };
+
+ subtype 'Ref'
+ => as 'Defined'
+ => where { ref($_) }
+ # no need to call parent - ref also checks for definedness
+ => inline_as { 'ref(' . $_[1] . ')' };
+
+ subtype 'Str'
+ => as 'Value'
+ => where { ref(\$_) eq 'SCALAR' || ref(\(my $val = $_)) eq 'SCALAR' }
+ => inline_as {
+ $_[0]->parent()->_inline_check($_[1])
+ . ' && ('
+ . 'ref(\\' . $_[1] . ') eq "SCALAR"'
+ . ' || ref(\\(my $val = ' . $_[1] . ')) eq "SCALAR"'
+ . ')'
+ };
+
+ my $value_type = Moose::Util::TypeConstraints::find_type_constraint('Value');
+ subtype 'Num'
+ => as 'Str'
+ => where {
+ my $val = $_;
+ ($val =~ /\A[+-]?[0-9]+\z/) ||
+ ( $val =~ /\A(?:[+-]?) #matches optional +- in the beginning
+ (?=[0-9]|\.[0-9]) #matches previous +- only if there is something like 3 or .3
+ [0-9]* #matches 0-9 zero or more times
+ (?:\.[0-9]+)? #matches optional .89 or nothing
+ (?:[Ee](?:[+-]?[0-9]+))? #matches E1 or e1 or e-1 or e+1 etc
+ \z/x );
+ }
+ => inline_as {
+ # the long Str tests are redundant here
+ #storing $_[1] in a temporary value,
+ #so that $_[1] won't get converted to a string for regex match
+ #see t/attributes/numeric_defaults.t for more details
+ 'my $val = '.$_[1].';'.
+ $value_type->_inline_check('$val')
+ .' && ( $val =~ /\A[+-]?[0-9]+\z/ || '
+ . '$val =~ /\A(?:[+-]?) #matches optional +- in the beginning
+ (?=[0-9]|\.[0-9]) #matches previous +- only if there is something like 3 or .3
+ [0-9]* #matches 0-9 zero or more times
+ (?:\.[0-9]+)? #matches optional .89 or nothing
+ (?:[Ee](?:[+-]?[0-9]+))? #matches E1 or e1 or e-1 or e+1 etc
+ \z/x ); '
+ };
+
+ subtype 'Int'
+ => as 'Num'
+ => where { (my $val = $_) =~ /\A-?[0-9]+\z/ }
+ => inline_as {
+ $value_type->_inline_check($_[1])
+ . ' && (my $val = ' . $_[1] . ') =~ /\A-?[0-9]+\z/'
+ };
+
+ subtype 'CodeRef'
+ => as 'Ref'
+ => where { ref($_) eq 'CODE' }
+ => inline_as { 'ref(' . $_[1] . ') eq "CODE"' };
+
+ subtype 'RegexpRef'
+ => as 'Ref'
+ => where( \&_RegexpRef )
+ => inline_as {
+ 'Moose::Util::TypeConstraints::Builtins::_RegexpRef(' . $_[1] . ')'
+ };
+
+ subtype 'GlobRef'
+ => as 'Ref'
+ => where { ref($_) eq 'GLOB' }
+ => inline_as { 'ref(' . $_[1] . ') eq "GLOB"' };
+
+ # NOTE: scalar filehandles are GLOB refs, but a GLOB ref is not always a
+ # filehandle
+ subtype 'FileHandle'
+ => as 'Ref'
+ => where {
+ (ref($_) eq "GLOB" && Scalar::Util::openhandle($_))
+ || (blessed($_) && $_->isa("IO::Handle"));
+ }
+ => inline_as {
+ '(ref(' . $_[1] . ') eq "GLOB" '
+ . '&& Scalar::Util::openhandle(' . $_[1] . ')) '
+ . '|| (Scalar::Util::blessed(' . $_[1] . ') '
+ . '&& ' . $_[1] . '->isa("IO::Handle"))'
+ };
+
+ subtype 'Object'
+ => as 'Ref'
+ => where { blessed($_) }
+ => inline_as { 'Scalar::Util::blessed(' . $_[1] . ')' };
+
+ subtype 'ClassName'
+ => as 'Str'
+ => where { is_class_loaded($_) }
+ # the long Str tests are redundant here
+ => inline_as { 'Class::Load::is_class_loaded(' . $_[1] . ')' };
+
+ subtype 'RoleName'
+ => as 'ClassName'
+ => where {
+ (Class::MOP::class_of($_) || return)->isa('Moose::Meta::Role');
+ }
+ => inline_as {
+ $_[0]->parent()->_inline_check($_[1])
+ . ' && do {'
+ . 'my $meta = Class::MOP::class_of(' . $_[1] . ');'
+ . '$meta && $meta->isa("Moose::Meta::Role");'
+ . '}'
+ };
+
+ $registry->add_type_constraint(
+ Moose::Meta::TypeConstraint::Parameterizable->new(
+ name => 'ScalarRef',
+ package_defined_in => __PACKAGE__,
+ parent =>
+ Moose::Util::TypeConstraints::find_type_constraint('Ref'),
+ constraint => sub { ref($_) eq 'SCALAR' || ref($_) eq 'REF' },
+ constraint_generator => sub {
+ my $type_parameter = shift;
+ my $check = $type_parameter->_compiled_type_constraint;
+ return sub {
+ return $check->( ${$_} );
+ };
+ },
+ inlined => sub {
+ 'ref(' . $_[1] . ') eq "SCALAR" '
+ . '|| ref(' . $_[1] . ') eq "REF"'
+ },
+ inline_generator => sub {
+ my $self = shift;
+ my $type_parameter = shift;
+ my $val = shift;
+ '(ref(' . $val . ') eq "SCALAR" || ref(' . $val . ') eq "REF") '
+ . '&& ' . $type_parameter->_inline_check('${(' . $val . ')}')
+ },
+ )
+ );
+
+ $registry->add_type_constraint(
+ Moose::Meta::TypeConstraint::Parameterizable->new(
+ name => 'ArrayRef',
+ package_defined_in => __PACKAGE__,
+ parent =>
+ Moose::Util::TypeConstraints::find_type_constraint('Ref'),
+ constraint => sub { ref($_) eq 'ARRAY' },
+ constraint_generator => sub {
+ my $type_parameter = shift;
+ my $check = $type_parameter->_compiled_type_constraint;
+ return sub {
+ foreach my $x (@$_) {
+ ( $check->($x) ) || return;
+ }
+ 1;
+ }
+ },
+ inlined => sub { 'ref(' . $_[1] . ') eq "ARRAY"' },
+ inline_generator => sub {
+ my $self = shift;
+ my $type_parameter = shift;
+ my $val = shift;
+
+ 'do {'
+ . 'my $check = ' . $val . ';'
+ . 'ref($check) eq "ARRAY" '
+ . '&& &List::Util::all('
+ . 'sub { ' . $type_parameter->_inline_check('$_') . ' }, '
+ . '@{$check}'
+ . ')'
+ . '}';
+ },
+ )
+ );
+
+ $registry->add_type_constraint(
+ Moose::Meta::TypeConstraint::Parameterizable->new(
+ name => 'HashRef',
+ package_defined_in => __PACKAGE__,
+ parent =>
+ Moose::Util::TypeConstraints::find_type_constraint('Ref'),
+ constraint => sub { ref($_) eq 'HASH' },
+ constraint_generator => sub {
+ my $type_parameter = shift;
+ my $check = $type_parameter->_compiled_type_constraint;
+ return sub {
+ foreach my $x ( values %$_ ) {
+ ( $check->($x) ) || return;
+ }
+ 1;
+ }
+ },
+ inlined => sub { 'ref(' . $_[1] . ') eq "HASH"' },
+ inline_generator => sub {
+ my $self = shift;
+ my $type_parameter = shift;
+ my $val = shift;
+
+ 'do {'
+ . 'my $check = ' . $val . ';'
+ . 'ref($check) eq "HASH" '
+ . '&& &List::Util::all('
+ . 'sub { ' . $type_parameter->_inline_check('$_') . ' }, '
+ . 'values %{$check}'
+ . ')'
+ . '}';
+ },
+ )
+ );
+
+ $registry->add_type_constraint(
+ Moose::Meta::TypeConstraint::Parameterizable->new(
+ name => 'Maybe',
+ package_defined_in => __PACKAGE__,
+ parent =>
+ Moose::Util::TypeConstraints::find_type_constraint('Item'),
+ constraint => sub {1},
+ constraint_generator => sub {
+ my $type_parameter = shift;
+ my $check = $type_parameter->_compiled_type_constraint;
+ return sub {
+ return 1 if not( defined($_) ) || $check->($_);
+ return;
+ }
+ },
+ inlined => sub {'1'},
+ inline_generator => sub {
+ my $self = shift;
+ my $type_parameter = shift;
+ my $val = shift;
+ '!defined(' . $val . ') '
+ . '|| (' . $type_parameter->_inline_check($val) . ')'
+ },
+ )
+ );
+}
+
+1;
+
+__END__
+
+=pod
+
+=for pod_coverage_needs_some_pod
+
+=cut