Aion

 view release on metacpan or  search on metacpan

lib/Aion/Types.pm  view on Meta::CPAN


sub as(@) { (as => @_) }
sub init_where(&@) { (init_where => @_) }
sub where(&@) { (where => @_) }
sub awhere(&@) { (awhere => @_) }
sub message(&@) { (message => @_) }

sub SELF() { $Aion::Type::SELF }
sub ARGS() {
	return $Aion::Type::SELF->{is_param_args} if $Aion::Type::SELF->{is_param_args};
	wantarray? @{$Aion::Type::SELF->{args}}: $Aion::Type::SELF->{args}
}
sub A() { $Aion::Type::SELF->{args}[0] }
sub B() { $Aion::Type::SELF->{args}[1] }
sub C() { $Aion::Type::SELF->{args}[2] }
sub D() { $Aion::Type::SELF->{args}[3] }

sub M() :lvalue { $Aion::Type::SELF->{M} }
sub N() :lvalue { $Aion::Type::SELF->{N} }

# Создание транслятора. У типа может быть сколько угодно трансляторов из других типов
# coerce Type, from OtherType, via {...}
sub coerce(@) {
	my ($type, %o) = @_;
	my ($from, $via) = delete @o{qw/from via/};

	die "coerce $type unused keys left: " . join ", ", keys %o if keys %o;
	die "coerce $type not Aion::Type!" unless UNIVERSAL::isa($type, "Aion::Type");
	die "coerce $type: from is'nt Aion::Type!" unless UNIVERSAL::isa($from, "Aion::Type");
	die "coerce $type: via is not subroutine!" unless ref $via eq "CODE";

	push @{$type->{coerce}}, [$from, $via];
	return;
}

sub from($) { (from => $_[0]) }
sub via(&) { (via => $_[0]) }

use constant DBL_MAX => do {
	my $ieee_dbl_max_str = '1.7976931348623157e+308';
	($ieee_dbl_max_str+0) =~ /inf/i? do {
		require Math::BigFloat;
		Math::BigFloat->new($ieee_dbl_max_str)
	}: $ieee_dbl_max_str+0
};

sub _8BITS() {
	undef *_8BITS;
	require Math::BigInt;
	my $_8bits = Math::BigInt->new(8);
	constant->import(_8BITS => $_8bits);
	$_8bits
}

BEGIN {

subtype "Any";
	subtype "Control", as &Any;
        subtype "Union[A, B...]", as &Control,
            where { my $val = $_; any { $_->include($val) } ARGS };
        subtype "Intersection[A, B...]", as &Control,
            where { my $val = $_; all { $_->include($val) } ARGS };
		subtype "Exclude[A]", as &Control,
			where { !A->test };
		subtype "Option[A]", as &Control,
			init_where { SELF->{is_option} = 1 }
			where { A->test };
		subtype "Wantarray[A, S]", as &Control,
			init_where { SELF->{is_wantarray} = 1 }
			where { ... };

	subtype "Item", as &Any;
		sub External($) {
			local $_ = $_[0][0];
			UNIVERSAL::isa($_, 'Aion::Type')? $_:
			defined($_) && ref $_ eq ""? Object([$_]): do {
				die "Not External[${\val_to_str($_)}]" unless reftype($_) eq "CODE" || overload::Method($_, '&{}');
				Aion::Type->new(
					name => 'External',
					as => &Item,
					args => $_[0],
					test => $_,
					UNIVERSAL::can($_, 'coerce')
						? (coerce => [[&Any, (sub { my ($ex) = @_; sub { $ex->coerce } })->($_)]])
						: (),
				)
			}
		}
		subtype "Bool", as &Item, where { ref $_ eq "" and /^(1|0|)\z/ };
		subtype "BoolLike", as &Item, where {
			return 1 if overload::Method($_, 'bool');
			my $m = overload::Method($_, '0+');
			Bool()->include($m ? $m->($_) : $_) };
		subtype "Enum[e...]", as &Item,
			init_where { M = +{ map {($_ => $_)} ARGS } }
			where { exists M->{$_} };
		subtype "Undef", as &Item, where { !defined $_ };
		subtype "Maybe[A]", as &Undef | A;
		subtype "Defined", as &Item, where { defined $_ };
			subtype "Value", as &Defined, where { "" eq ref $_ };
				subtype "Version", as &Value, where { "VSTRING" eq ref \$_ };
				subtype "Str", as &Value, where { "SCALAR" eq ref \$_ };
					subtype "Uni", as &Str,	where { utf8::is_utf8($_) || /[\x80-\xFF]/a };
					subtype "Bin", as &Str, where { !utf8::is_utf8($_) && !/[\x80-\xFF]/a };
					subtype "NonEmptyStr", as &Str,	where { /\S/ };
					subtype "StartsWith[start]", as &Str,
						init_where { M = qr/^${\ quotemeta A}/ },
						where { $_ =~ M };
					subtype "EndsWith[end]", as &Str,
						init_where { N = qr/${\ quotemeta A}$/ },
						where { $_ =~ N };
					subtype "Email", as &Str, where { /@/ };
					subtype "Tel", as &Str, where { /^\+\d{7,}\z/ };
					subtype "Url", as &Str, where { /^https?:\/\// };
					subtype "Path", as &Str, where { /^\// };
					subtype "Html", as &Str, where { /^\s*<(!doctype\s+html|html)\b/i };
					subtype "StrDate", as &Str, where { /^\d{4}-\d{2}-\d{2}\z/ };
					subtype "StrDateTime", as &Str, where { /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\z/ };
					subtype "StrMatch[regexp]", as &Str, where { $_ =~ A };
					subtype "PackageName", as &Str, where { no utf8; use bytes; /^(?:[a-z]\w*(?:::[a-z]\w*)*)\z/ia };
						subtype "ClassName", as &PackageName, where { !!$_->can('new') };

lib/Aion/Types.pm  view on Meta::CPAN

						subtype "LimKeys[from, to?]", as &HashLike,
							init_where { unshift @{&ARGS}, 0 if @{&ARGS} == 1; }
							where { A <= scalar keys %$_ && scalar keys %$_ <= B };
		
			subtype "Like", as &Str | &Object;
				subtype "HasMethods[m...]", as &Like,
					where { my $x = $_; all { $x->can($_) } ARGS };
				subtype "Overload`[m...]", as &Like,
					where { !!overload::Overloaded($_) }
					awhere { my $x = $_; all { overload::Method($x, $_) } ARGS };
				subtype "InstanceOf[class...]", as &Like, where { my $x = $_; all { $x->isa($_) } ARGS };
				subtype "ConsumerOf[role...]", as &Like, where { my $x = $_; all { $x->DOES($_) } ARGS };
				subtype "StrLike", as &Like, where { !blessed($_) or !!overload::Method($_, '""') };
					subtype "Len[from, to?]", as &StrLike,
						init_where { unshift @{&ARGS}, 0 if @{&ARGS} == 1; }
						where { A <= length($_) && length($_) <= B };
	
				subtype "NumLike", as &Num | &Object & Overload(["0+"]);
					sub Opened($) { Aion::Type::Lim->from(ref $_[0] eq "ARRAY"? $_[0][0]: $_[0]) };
					subtype "Range[from, to]", as &NumLike,
						init_where {
							SELF->{args}[0] = A->inc if UNIVERSAL::isa(A, 'Aion::Type::Lim');
							SELF->{args}[1] = B->dec if UNIVERSAL::isa(B, 'Aion::Type::Lim');
						}
						where { A <= $_ && $_ <= B };
						subtype "Float", as Range([-(POSIX::FLT_MAX), POSIX::FLT_MAX]);
						subtype "Double", as Range([-(DBL_MAX), DBL_MAX]);
						subtype "Bytes[n]", as Range([]),
							init_where {
								my $_8bits = A < 8? 8: _8BITS;
								my $N = 1 << ($_8bits * A - 1);
								SELF->{as} = Range([-$N, $N-1]);
							};
						subtype "PositiveBytes[n]", as Range([]),
							init_where {
								my $_8bits = A < 8? 8: _8BITS;
								my $M = 1 << ($_8bits*A);
								SELF->{as} = Range([0, $M-1]);
							};

	coerce &Str => from &Undef => via { "" };
	coerce &Int => from &Num => via { int($_+($_ < 0? -.5: .5)) };
	coerce &Bool => from &Any => via { !!$_ };

	subtype 'Join[separator]', as &Str;
	coerce &Join, from &ArrayRef, via { join A, @$_ };

	subtype 'Split[separator]', as &ArrayRef;
	coerce &Split, from &Str, via { [split A, $_] };

	coerce &Rat => from &StrRat => via { Math::BigRat->new($_) };

	subtype "PositiveNum", as &Num & Range([0, 'Inf']);
	subtype "PositiveInt", as &Int & Range([0, 'Inf']);
	subtype "Nat", as &Int & Range([1, 'Inf']);

	my $_none = ~&Any;
	sub None() { $_none }
};

$_->keyfn(\&Aion::Type::typed_sorted_args_key) for Union[], Intersection[];
(Enum[])->keyfn(\&Aion::Type::sorted_args_key);

%Aion::Type::range_lbound = map { (Scalar::Util::refaddr $_->{coerce} => $_->{name} eq 'Range'? '-Inf': 0) } Range[], Lim[], LimKeys[], Len[];

1;

__END__

=encoding utf-8

=head1 NAME

Aion::Types - a library of standard validators and it is used to create new validators

=head1 SYNOPSIS

	use Aion::Types;
	
	BEGIN {
		subtype SpeakOfKitty => as StrMatch[qr/\bkitty\b/i],
			message { "Speak is'nt included kitty!" };
	}
	
	"Kitty!" ~~ SpeakOfKitty # -> 1
	"abc"    ~~ SpeakOfKitty # -> ""
	
	SpeakOfKitty->validate("abc", "This") # @-> Speak is'nt included kitty!
	
	
	BEGIN {
		subtype 'IntOrArrayRef[len, B]',
			as Int & Range[5, A]
				| ArrayRef[B & Len[A]];
	}
	
	35 ~~ IntOrArrayRef[35, Tel] # -> 1
	35 ~~ IntOrArrayRef[34, Tel] # -> ""
	
	'+23456789'  ~~ Tel # -> 1
	'+234567890' ~~ Tel # -> 1
	'+23456789'  ~~ (Tel & Len[9]) # -> 1
	'+234567890' ~~ (Tel & Len[9]) # -> ""
	
	['+23456789',  '+23456789'] ~~ IntOrArrayRef[9, Tel] # -> 1
	['+234567890', '+23456789'] ~~ IntOrArrayRef[9, Tel] # -> ""
	
	"" ~~ IntOrArrayRef[8, Tel]  # -> ""
	
	
	coerce IntOrArrayRef[35, Str], from Num, via { int($_ + .5) };
	
	IntOrArrayRef([35, Str])->coerce(5.5) # => 6
	
	5.5 >> IntOrArrayRef[35, Str] # => 6
	
	(Tel & Len[9]) < (Tel & Len[10]) # => 1

=head1 DESCRIPTION

This module exports routines:

=over

=item * C<subtype>, C<as>, C<init_where>, C<where>, C<awhere>, C<message> - for creating validators.

=item * C<SELF>, C<ARGS>, C<A>, C<B>, C<C>, C<D>, C<M>, C<N> - for use in validators of a type and its arguments.

=item * C<coerce>, C<from>, C<via> - to create a value converter from one class to another.

=back

Validator hierarchy:

	Any
		Control
			Union[A, B...]
			Intersection[A, B...]
			Exclude[A...]
			Option[A]
			Wantarray[A, B]
		Item
			External[type]
			Bool
			BoolLike
			Enum[e...]
			Maybe[A]
			Undef
			Defined
				Value
					Version
					Str
						Uni
						Bin
						NonEmptyStr
						StartsWith[start]
						EndsWith[end]
						Email
						Tel
						Url
						Path
						Html
						StrDate
						StrDateTime
						StrMatch[regexp]
						PackageName
							ClassName
							RoleName
						Join[separator]
						Split[separator]
						StrRat
						Num
							PositiveNum
							Int
								PositiveInt
								Nat
				Ref
					Tied`[class]
					LValueRef
					FormatRef
					CodeRef
						NamedCode[subname]
						ProtoCode[prototype]
						ForwardRef
						ImplementRef
						Isa[A...]
					RegexpRef
					ValueRef`[A]
						ScalarRef`[A]
						RefRef`[A]
					GlobRef
						FileHandle
					ArrayRef`[A]
						Tuple[A...]
						CycleTuple[A...]
					HashRef`[A]
						Map[A => B]
						Dict[k => A, ...]
					Object`[class]
						Me
						Rat
					RegexpLike
					CodeLike
					ArrayLike`[A]
						Lim[from?, to]
					HashLike`[A]
						HasProp[p...]
						LimKeys[from?, to]
				Like
					HasMethods[m...]
					Overload`[m...]
					InstanceOf[class...]
					ConsumerOf[role...]
					StrLike
						Len[from?, to]
					NumLike
						Range[from, to]
							Float
							Double
							Bytes[n]
							PositiveBytes[n]

=head1 SUBROUTINES

=head2 subtype ($name, @paraphernalia)

Creates a new type.

	BEGIN {
		subtype One => where { $_ == 1 } message { "Actual 1 only!" };
	}
	
	1 ~~ One	 # -> 1
	0 ~~ One	 # -> ""
	eval { One->validate(0) }; $@ # ~> Actual 1 only!

C<where> and C<message> are syntactic sugar, and C<subtype> can be used without them.

	BEGIN {
		subtype Many => (where => sub { $_ > 1 });
	}
	
	2 ~~ Many  # -> 1
	
	eval { subtype Many => (where1 => sub { $_ > 1 }) }; $@ # ~> subtype Many unused keys left: where1
	
	eval { subtype 'Many' }; $@ # ~> subtype Many: main::Many exists!

=head2 as ($super_type)

Used with C<subtype> to extend the created C<$super_type> type.

C<as> can accept type expressions combined with set-theoretic operators. It also allows the parameters C<A>, C<B>, C<C>, C<D>, C<ARGS>, C<SELF>, C<M> and C<N>. C<M> and C<N> can be set in the C<init_where> section of the parameterized types included ...

	BEGIN {
		subtype 'Top[to]', as Range[0, A];
	}
	
	+3.0 ~~ Top[3] # -> 1
	+3.1 ~~ Top[3] # -> ""
	+0.0 ~~ Top[3] # -> 1
	-0.1 ~~ Top[3] # -> ""
	
	BEGIN {
		subtype 'RedColor', as Enum['red'];
		subtype 'BlueColor', as Enum['blue'];
	}
	BEGIN {
		subtype 'RedBlue', as RedColor | BlueColor;
	}
	
	'red'   ~~ RedBlue # -> 1
	'blue'  ~~ RedBlue # -> 1
	'green' ~~ RedBlue # -> ""
	
	BEGIN {
		subtype 'RedBlueOther[colors...]', as ~RedBlue & Enum[ARGS];
	}
	
	'red' ~~ RedBlueOther['red'] # -> ""
	'green' ~~ RedBlueOther['red', 'green'] # -> 1

=head2 init_where ($code)

Initializes a type with new arguments. Used with C<subtype>.

Initialization is lazy. This means that it will work in the C<test> method or similar.

	BEGIN {
		subtype 'LessThen[n]',
			init_where { Num->validate(A, "Argument LessThen[n]") }
			where { $_ < A };
	}
	
	eval { LessThen["string"] }; $@  # ^=> Argument LessThen[n]
	
	5 ~~ LessThen[5]  # -> ""

=head2 where ($code)

Uses C<$code> as a test. The value for the test is passed to C<$_>.

	BEGIN {
		subtype 'Two',
			where { $_ == 2 };
	}
	
	2 ~~ Two # -> 1
	3 ~~ Two # -> ""

=head2 awhere ($code)

Used with C<subtype>.

If the type can be with or without arguments, then it is used to check the set with arguments, and C<where> - without.

	BEGIN {
		subtype 'GreatThen`[num]',
			where { $_ > 0 }
			awhere { $_ > A }
		;
	}
	
	0 ~~ GreatThen # -> ""
	1 ~~ GreatThen # -> 1
	
	3 ~~ GreatThen[3] # -> ""
	4 ~~ GreatThen[3] # -> 1

Required if arguments are optional.

	subtype 'Ex`[a]', where {} # @-> subtype Ex`[a]: needs an awhere
	subtype 'Ex', awhere {} # @-> subtype Ex: awhere is excess
	
	BEGIN {
		subtype 'MyEnum`[item...]',
			as Str,
			awhere { $_ ~~ scalar ARGS }
		;
	}
	
	"ab" ~~ MyEnum[qw/ab cd/] # -> 1

=head2 SELF

Current type. C<SELF> is used in C<init_where>, C<where> and C<awhere>.

=head2 ARGS

Arguments of the current type. In a scalar context, it returns a reference to an array, and in an array context, it returns a list. Used in C<init_where>, C<where> and C<awhere>.

=head2 A

A, B, C, D – the first, second, third and fifth type argument.

	BEGIN {
		subtype "Seria[a,b,c,d]", where { A < B && B < $_ && $_ < C && C < D };
	}
	
	2.5 ~~ Seria[1,2,3,4] # -> 1

Used in C<init_where>, C<where> and C<awhere>.

=head1 B

Second type argument.

=head1 C

Third type argument.

=head1 D

The fourth type argument.

=head2 M

C<M> and C<N> are shorthand for C<< SELF-E<gt>{M} >> and C<< SELF-E<gt>{N} >>.

	BEGIN {
		subtype "BeginAndEnd[begin, end]",
			init_where {
				N = qr/^${\ quotemeta A}/;
				M = qr/${\ quotemeta B}$/;
			}
			where { $_ =~ N && $_ =~ M };
	}
	
	"Hi, my dear!" ~~ BeginAndEnd["Hi,", "!"]; # -> 1
	"Hi my dear!" ~~ BeginAndEnd["Hi,", "!"];  # -> ""
	
	"" . BeginAndEnd["Hi,", "!"] # => BeginAndEnd['Hi,', '!']

=head2 N

Shorthand for C<< SELF-E<gt>{N} >>.

=head2 message ($code)

Used with C<subtype> to print an error message if the value excludes the type. C<$code> uses: C<SELF> - the current type, C<ARGS>, C<A>, C<B>, C<C>, C<D> - type arguments (if any) and a test value in C<$_>. It can be converted to a string using C<< S...

=head2 coerce ($type, from => $from, via => $via)

Adds a new cast (C<$via>) to C<$type> from C<$from> type.

	BEGIN {
		subtype Four => where {4 eq $_};
	}
	
	"4a" ~~ Four # -> ""
	
	Four->coerce("4a") # -> "4a"
	
	coerce Four, from Str, via { 0+$_ };

lib/Aion/Types.pm  view on Meta::CPAN

	Str->coerce(undef) # -> ""
	
	# Int from Num — rounded integer
	Int->coerce(2.5)  # -> 3
	Int->coerce(-2.5) # -> -3
	
	# Bool from Any — 1 or ""
	Bool->coerce([]) # -> 1
	Bool->coerce(0)  # -> ""

=head2 from ($type)

Syntactic sugar for C<coerce>.

=head2 via ($code)

Syntactic sugar for C<coerce>.

=head1 ATTRIBUTES

=head2 :Isa (@signature)

Checks the signature of a subroutine: arguments and results.

	sub minint($$) : Isa(Int => Int => Int) {
		my ($x, $y) = @_;
		$x < $y? $x : $y
	}
	
	minint 6, 5; # -> 5
	eval {minint 5.5, 2}; $@ # ~> Arguments of method `minint` must have the type Tuple\[Int, Int\]\.
	
	sub half($) : Isa(Int => Int) {
		my ($x) = @_;
		$x / 2
	}
	
	half 4; # -> 2
	eval {half 5}; $@ # ~> Return of method `half` must have the type Int. The it is 2.5

=head1 TYPES

=head2 Any

The top level type in the hierarchy. Compares everything.

The bottom type can be obtained as C<~Any>.

=head2 Control

The top-level type in hierarchy constructors creates new types from any types.

=head2 Union[A, B...]

Union of several types. Similar to the C<$type1 | $type2>.

	33  ~~ Union[Int, Ref] # -> 1
	[]  ~~ Union[Int, Ref] # -> 1
	"a" ~~ Union[Int, Ref] # -> ""

=head2 Intersection[A, B...]

The intersection of several types. Similar to the C<$type1 & $type2> operator.

	15 ~~ Intersection[Int, StrMatch[/5/]] # -> 1

=head2 Exclude[A]

Type value exception. Similar to the C<~$type> operator.

	-5  ~~ Exclude[PositiveInt] # -> 1
	"a" ~~ Exclude[PositiveInt] # -> 1
	5   ~~ Exclude[PositiveInt] # -> ""
	5.5 ~~ Exclude[PositiveInt] # -> 1

=head2 Option[A]

Additional keys in C<Dict>.

	{a=>55} ~~ Dict[a=>Int, b => Option[Int]]          # -> 1
	{a=>55, b=>31} ~~ Dict[a=>Int, b => Option[Int]]   # -> 1
	{a=>55, b=>31.5} ~~ Dict[a=>Int, b => Option[Int]] # -> ""

=head2 Wantarray[A, S]

If the routine returns different values in array and scalar contexts, then the C<Wantarray> type is used with type C<A> for the array context and type C<S> for the scalar context.

	sub arr : Isa(PositiveInt => Wantarray[ArrayRef[PositiveInt], PositiveInt]) {
		my ($n) = @_;
		wantarray? 1 .. $n: $n
	}
	
	my @array = arr(3);
	my $scalar = arr(3);
	
	\@array # --> [1,2,3]
	$scalar  # -> 3

=head2 Item

The top-level type in the hierarchy of scalar types.

=head2 External[type]

Sets C<type> to C<Aion::Type>.

=over

=item * If C<type> is C<Aion::Type>, then returns it unchanged.

=item * If C<type> is a string, then wraps it in C<Object>.

=item * If C<type> can be called, then wraps it in C<< Aion::Type-E<gt>new(test =E<gt> $type, ...) >>. And if it has a C<coerce> method, it will use it for transformations. Thanks to this, it is possible to use external types like C<Type::Tiny> in th...

=back

	External['Aion'] # -> Object['Aion']
	External[sub { /^x/ }] ~~ 'xyz' # -> 1
	
	package MyInt {
		use overload "&{}" => sub {
			sub { /^[+-]?[0-9]+$/ }
		};
		
		sub coerce { /\./? int($_): $_ }

lib/Aion/Types.pm  view on Meta::CPAN

An object or class has listed methods. In addition to them, there may be others.

	package HasMethodsExample {
		sub x1 {}
		sub x2 {}
	}
	
	"HasMethodsExample" ~~ HasMethods[qw/x1 x2/]			# -> 1
	bless({}, "HasMethodsExample") ~~ HasMethods[qw/x1 x2/] # -> 1
	bless({}, "HasMethodsExample") ~~ HasMethods[qw/x1/]	# -> 1
	"HasMethodsExample" ~~ HasMethods[qw/x3/]				# -> ""
	"HasMethodsExample" ~~ HasMethods[qw/x1 x2 x3/]			# -> ""
	"HasMethodsExample" ~~ HasMethods[qw/x1 x3/]			# -> ""

=head2 Overload`[op...]

An object or class with overloaded operators.

	package OverloadExample {
		use overload '""' => sub { "abc" };
	}
	
	"OverloadExample" ~~ Overload            # -> 1
	bless({}, "OverloadExample") ~~ Overload # -> 1
	"A" ~~ Overload                          # -> ""
	bless({}, "A") ~~ Overload               # -> ""

And the specified operators are overloaded.

	"OverloadExample" ~~ Overload['""'] # -> 1
	"OverloadExample" ~~ Overload['|']  # -> ""

=head2 InstanceOf[A...]

A class or object inherits classes from a list.

	package Animal {}
	package Cat { our @ISA = qw/Animal/ }
	package Tiger { our @ISA = qw/Cat/ }
	
	
	"Tiger" ~~ InstanceOf['Animal', 'Cat'] # -> 1
	"Tiger" ~~ InstanceOf['Tiger']         # -> 1
	"Tiger" ~~ InstanceOf['Cat', 'Dog']    # -> ""

=head2 ConsumerOf[A...]

A class or object has the specified roles.

	package NoneExample {}
	package RoleExample { sub DOES { $_[1] ~~ [qw/Role1 Role2/] } }
	
	'RoleExample' ~~ ConsumerOf[qw/Role1/] # -> 1
	'RoleExample' ~~ ConsumerOf[qw/Role2 Role1/] # -> 1
	bless({}, 'RoleExample') ~~ ConsumerOf[qw/Role3 Role2 Role1/] # -> ""
	
	'NoneExample' ~~ ConsumerOf[qw/Role1/] # -> ""

=head2 BoolLike

Tests for 1, 0, "", undef, or an object with an overloaded C<bool> or C<0+> operator as C<JSON::PP::Boolean>. In the second case, it calls the C<0+> operator and checks the result as C<Bool>.

C<BoolLike> calls the C<0+> operator and checks the result.

	package BoolLikeExample {
		use overload '0+' => sub { ${$_[0]} };
	}
	
	bless(\(my $x = 1 ), 'BoolLikeExample') ~~ BoolLike # -> 1
	bless(\(my $x = 11), 'BoolLikeExample') ~~ BoolLike # -> ""
	
	1 ~~ BoolLike     # -> 1
	0 ~~ BoolLike     # -> 1
	"" ~~ BoolLike    # -> 1
	undef ~~ BoolLike # -> 1
	
	package BoolLike2Example {
		use overload 'bool' => sub { ${$_[0]} };
	}
	
	bless(\(my $x = 1 ), 'BoolLike2Example') ~~ BoolLike # -> 1
	bless(\(my $x = 11), 'BoolLike2Example') ~~ BoolLike # -> 1

=head2 StrLike

A string or object overloaded with the C<""> operator.

	"" ~~ StrLike # -> 1
	
	package StrLikeExample {
		use overload '""' => sub { "abc" };
	}
	
	bless({}, "StrLikeExample") ~~ StrLike # -> 1
	
	{} ~~ StrLike # -> ""

=head2 RegexpLike

A regular expression or object with an overload of the C<qr> operator.

	ref(qr//)  # => Regexp
	Scalar::Util::reftype(qr//) # => REGEXP
	
	my $regex = bless qr//, "A";
	Scalar::Util::reftype($regex) # => REGEXP
	
	$regex ~~ RegexpLike # -> 1
	qr// ~~ RegexpLike   # -> 1
	"" ~~ RegexpLike     # -> ""
	
	package RegexpLikeExample {
	 use overload 'qr' => sub { qr/abc/ };
	}
	
	"RegexpLikeExample" ~~ RegexpLike # -> ""
	bless({}, "RegexpLikeExample") ~~ RegexpLike # -> 1

=head2 CodeLike

A subroutine or object with an overload of the C<&{}> operator.



( run in 0.872 second using v1.01-cache-2.11-cpan-6aa56a78535 )