Aion
view release on metacpan or search on metacpan
lib/Aion/Types.pm view on Meta::CPAN
package Aion::Types;
# ТипÑ-валидаÑоÑÑ Ð´Ð»Ñ Aion
use common::sense;
use Aion::Meta::Util qw/subref_is_reachable/;
use Aion::Type;
use List::Util qw/all any first/;
use Exporter qw/import/;
require overload;
use Scalar::Util qw/looks_like_number reftype refaddr blessed/;
use Sub::Util qw//;
our @EXPORT = our @EXPORT_OK = grep {
*{$Aion::Types::{$_}}{CODE} && !/^(_|(NaN|import|all|any|first|looks_like_number|reftype|refaddr|blessed|subref_is_reachable)\z)/n
} keys %Aion::Types::;
# ÐбÑабаÑÑваем аÑÑибÑÑ :Isa
sub MODIFY_CODE_ATTRIBUTES {
my ($pkg, $referent, @attributes) = @_;
grep { /^Isa\((.*)\)\z/s? do { _Isa($pkg, $referent, $1); 0 }: 1 } @attributes
}
sub _Isa {
my ($pkg, $referent, $data) = @_;
my $subname = Sub::Util::subname $referent;
$subname =~ s/^.*:://;
die "Anonymous subroutine cannot use :Isa!" if $subname eq '__ANON__';
my @signature = eval "package $pkg; map { UNIVERSAL::isa(\$_, 'Aion::Type')? \$_: __PACKAGE__->can(\$_)? __PACKAGE__->can(\$_)->(): Aion::Types::External([\$_]) } ($data)";
die if $@;
die "$pkg\::$subname has no return type!" if @signature == 0;
require Aion::Meta::Subroutine;
my $subroutine = Aion::Meta::Subroutine->new(
pkg => $pkg,
subname => $subname,
signature => \@signature,
referent => $referent,
);
if(!subref_is_reachable($referent)) {
$Aion::META{$pkg}{require}{$subname} = $subroutine;
} else {
my $require = delete $Aion::META{$pkg}{require}{$subname};
$require->compare($subroutine) if $require;
my $overload = $Aion::META{$pkg}{subroutine}{$subname};
$overload->compare($subroutine) if $overload;
$subroutine->wrap_sub;
}
}
BEGIN {
my $TRUE = sub {1};
my $INIT_ARGS = sub { @{&ARGS} = map External([$_]), @{&ARGS} };
my $INIT_KW_ARGS = sub { @{&ARGS} = List::Util::pairmap { $a => External([$b]) } @{&ARGS} };
# Создание Ñипа
sub subtype(@) {
my $subtype = shift;
my %o = @_;
my ($as, $init_where, $where, $awhere, $message) = delete @o{qw/as init_where where awhere message/};
$as = External([$as]) if defined $as;
die "subtype $subtype unused keys left: " . join ", ", keys %o if keys %o;
die "subtype format is Name or Name[args] or Name`[args]" if $subtype !~ /^([A-Z_]\w*)(?:(\`)?\[(.*)\])?$/i;
my ($name, $is_maybe_arg, $is_arg) = ($1, $2, $3);
lib/Aion/Types.pm view on Meta::CPAN
subtype "Nat", as &Int, where { $_ > 0 };
subtype "Ref", as &Defined, where { "" ne ref $_ };
subtype "Tied`[class]", as &Ref,
where { my $ref = reftype($_); !!(
$ref eq "HASH"? tied %$_:
$ref eq "ARRAY"? tied @$_:
$ref eq "SCALAR"? tied $$_:
0
) }
awhere { my $ref = reftype($_);
$ref eq "HASH"? A eq ref tied %$_:
$ref eq "ARRAY"? A eq ref tied @$_:
$ref eq "SCALAR"? A eq ref tied $$_:
""
};
subtype "LValueRef", as &Ref, where { ref $_ eq "LVALUE" };
subtype "FormatRef", as &Ref, where { ref $_ eq "FORMAT" };
subtype "CodeRef", as &Ref, where { ref $_ eq "CODE" };
subtype "NamedCode[subname]", as &CodeRef, where { Sub::Util::subname($_) ~~ A };
subtype "ProtoCode[prototype]", as &CodeRef, where { Sub::Util::prototype($_) ~~ A };
subtype "ForwardRef", as &CodeRef, where { !subref_is_reachable($_) };
subtype "ImplementRef", as &CodeRef, where { subref_is_reachable($_) };
subtype "Isa[type...]", as &CodeRef,
init_where {
my $pkg = caller(2);
SELF->{args} = [ map { External([UNIVERSAL::isa($_, 'Aion::Type')? $_: $pkg->can($_)? $pkg->can($_)->(): $_]) } ARGS ]
}
where {
my $subroutine = $Aion::Isa{pack "J", refaddr $_} or return "";
my $signature = $subroutine->{signature};
my $args = ARGS;
return "" if @$signature != @$args;
my $i = 0;
for my $type (@$args) {
return "" unless $signature->[$i++] eq $type;
}
1
};
subtype "RegexpRef", as &Ref, where { ref $_ eq "Regexp" };
subtype "ValueRef`[A]", as &Ref,
where { ref($_) ~~ ["SCALAR", "REF"] }
awhere { ref($_) ~~ ["SCALAR", "REF"] && A->include($$_) };
subtype "ScalarRef`[A]", as &ValueRef,
where { ref $_ eq "SCALAR" }
awhere { ref $_ eq "SCALAR" && A->include($$_) };
subtype "RefRef`[A]", as &ValueRef,
where { ref $_ eq "REF" }
awhere { ref $_ eq "REF" && A->include($$_) };
subtype "GlobRef", as &Ref, where { ref $_ eq "GLOB" };
subtype "FileHandle", as &GlobRef,
where { !!*$_{IO} };
subtype "ArrayRef`[A]", as &Ref,
where { ref $_ eq "ARRAY" }
awhere { my $A = A; ref $_ eq "ARRAY" && all { $A->test } @$_ };
subtype "HashRef`[A]", as &Ref,
where { ref $_ eq "HASH" }
awhere { my $A = A; ref $_ eq "HASH" && all { $A->test } values %$_ };
subtype "Object`[class]", as &Ref,
where { blessed($_) ne "" }
awhere { blessed($_) && $_->isa(A) };
subtype "Me", as &Object,
init_where { SELF->{me} = caller(2) }
where { UNIVERSAL::isa($_, SELF->{me}) };
subtype "Map[K, V]", as &HashRef,
where {
my ($K, $V) = ARGS;
while(my ($k, $v) = each %$_) {
return "" unless $K->include($k) && $V->include($v);
}
return 1;
};
my $tuple_args = ArrayRef([Object(['Aion::Type'])]);
subtype "Tuple[A...]", as &ArrayRef,
init_where { $tuple_args->validate(scalar ARGS, "Arguments Tuple[A...]") }
where {
my $k = 0;
for my $A (ARGS) {
return "" if $A->exclude($_->[$k++]);
}
$k == @$_
};
subtype "CycleTuple[A...]", as &ArrayRef,
init_where { $tuple_args->validate(scalar ARGS, "Arguments CycleTuple[A...]") }
where {
my $k = 0;
while($k < @$_) {
for my $A (ARGS) {
return "" if $A->exclude($_->[$k++]);
}
}
$k == @$_
};
my $dict_args = CycleTuple([&Str, Object(['Aion::Type'])]);
subtype "Dict[k => A, ...]", as &HashRef,
init_where { $dict_args->validate(scalar ARGS, "Arguments Dict[k => A, ...]") }
where {
my $count = 0; my $k;
for my $A (ARGS) {
$k = $A, next unless ref $A;
if(exists $_->{$k}) {
return "" if $A->exclude($_->{$k});
$count++;
} else {
return "" if !exists $A->{is_option};
}
}
$count == keys %$_
};
subtype "RegexpLike", as &Ref,
where { reftype($_) eq "REGEXP" || !!overload::Method($_, 'qr') };
subtype "CodeLike", as &Ref,
where { reftype($_) eq "CODE" || !!overload::Method($_, '&{}') };
subtype "ArrayLike`[A]", as &Ref,
where { reftype($_) eq "ARRAY" || !!overload::Method($_, '@{}') }
awhere { &ArrayLike->test && do { my $A = A; all { $A->test } @$_ }};
my $init_limit = sub { if(@{&ARGS} == 1) { SELF->{min} = 0; SELF->{max} = A } else { SELF->{min} = A; SELF->{max} = B } };
subtype "Lim[from, to?]", as &ArrayLike,
init_where => $init_limit,
where { SELF->{min} <= @$_ && @$_ <= SELF->{max} };
subtype "HashLike`[A]", as &Ref,
where { reftype($_) eq "HASH" || !!overload::Method($_, "%{}") }
awhere { &HashLike->test && do { my $A = A; all { $A->test } values %$_ }};
subtype "HasProp[p...]", as &HashLike,
where { my $x = $_; all { exists $x->{$_} } ARGS };
subtype "LimKeys[from, to?]", as &HashLike,
init_where => $init_limit,
where { SELF->{min} <= scalar keys %$_ && scalar keys %$_ <= SELF->{max} };
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 => $init_limit,
where { SELF->{min} <= length($_) && length($_) <= SELF->{max} };
subtype "NumLike", as &Like, where { looks_like_number($_) };
subtype "Float", as &NumLike, where { -3.402823466E+38 <= $_ && $_ <= 3.402823466E+38 };
my $_from; my $_to;
subtype "Double", as &NumLike, where {
$_from //= do { require Math::BigFloat; Math::BigFloat->new('-1.7976931348623157e+308') };
$_to //= do { require Math::BigFloat; Math::BigFloat->new( '1.7976931348623157e+308') };
$_from <= $_ && $_ <= $_to;
};
subtype "Range[from, to]", as &NumLike, where { A <= $_ && $_ <= B };
my $_8bits;
subtype "Bytes[n]", as &NumLike,
init_where {
my $bits = A < 8? 8: ($_8bits //= do {
require Math::BigInt;
Math::BigInt->new(8)
});
my $N = 1 << ($bits * A - 1);
N = -$N;
M = $N-1;
}
where { N <= $_ && $_ <= M };
subtype "PositiveBytes[n]", as &NumLike,
init_where {
my $bits = A < 8? 8: ($_8bits //= do {
require Math::BigInt;
Math::BigInt->new(8)
});
M = (1 << ($bits*A)) - 1;
}
where { 0 <= $_ && $_ <= M };
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, $_] };
subtype "Rat", as 'Math::BigRat';
coerce &Rat => from &StrRat => via { Math::BigRat->new($_) };
};
1;
__END__
=encoding utf-8
=head1 NAME
Aion::Types - a library of standard validators and it is used to create new validators
lib/Aion/Types.pm view on Meta::CPAN
5.5 ~~ Exclude[PositiveInt] # -> 1
If C<Exclude> has many arguments, then it is analogous to C<~ ($type1 | $type2 ...)>.
-5 ~~ Exclude[PositiveInt, Enum[-2]] # -> 1
-2 ~~ Exclude[PositiveInt, Enum[-2]] # -> ""
0 ~~ Exclude[PositiveInt, Enum[-2]] # -> ""
=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 @a = arr(3);
my $s = arr(3);
\@a # --> [1,2,3]
$s # -> 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($_): $_ }
}
my $myint = bless {}, 'MyInt';
External([$myint]) ~~ '+123' # -> 1
External([$myint])->coerce(10.1) # => 10
External([$myint])->coerce('abc') # => abc
=head2 Bool
C<1> is true. C<0>, C<""> or C<undef> is false.
1 ~~ Bool # -> 1
0 ~~ Bool # -> 1
undef ~~ Bool # -> 1
"" ~~ Bool # -> 1
2 ~~ Bool # -> ""
[] ~~ Bool # -> ""
=head2 Enum[A...]
Enumeration.
3 ~~ Enum[1,2,3]; # -> 1
"cat" ~~ Enum["cat", "dog"]; # -> 1
4 ~~ Enum[1,2,3]; # -> ""
=head2 Maybe[A]
C<undef> or type in C<[]>.
undef ~~ Maybe[Int] # -> 1
4 ~~ Maybe[Int] # -> 1
"" ~~ Maybe[Int] # -> ""
=head2 Undef
Only C<undef>.
undef ~~ Undef # -> 1
0 ~~ Undef # -> ""
=head2 Defined
Everything except C<undef>.
\0 ~~ Defined # -> 1
undef ~~ Defined # -> ""
=head2 Value
Defined values without references.
3 ~~ Value # -> 1
\3 ~~ Value # -> ""
undef ~~ Value # -> ""
=head2 Len[from, to?]
Specifies a length value from C<from> to C<to>, or from 0 to C<from> if C<to> is missing.
"1234" ~~ Len[3] # -> ""
lib/Aion/Types.pm view on Meta::CPAN
$N ~~ Bytes[8] # -> ""
require Math::BigInt;
my $N17 = 1 << (8*Math::BigInt->new(17) - 1);
((-$N17-1) . "") ~~ Bytes[17] # -> ""
(-$N17 . "") ~~ Bytes[17] # -> 1
(($N17-1) . "") ~~ Bytes[17] # -> 1
($N17 . "") ~~ Bytes[17] # -> ""
=head2 PositiveInt
Positive integers.
+0 ~~ PositiveInt # -> 1
-0 ~~ PositiveInt # -> 1
55 ~~ PositiveInt # -> 1
-1 ~~ PositiveInt # -> ""
=head2 PositiveBytes[N]
Calculates the maximum number that will fit in C<N> bytes (assuming there is no negative bit in the bytes) and checks the limit from 0 to that number.
-1 ~~ PositiveBytes[1] # -> ""
0 ~~ PositiveBytes[1] # -> 1
255 ~~ PositiveBytes[1] # -> 1
256 ~~ PositiveBytes[1] # -> ""
-1 ~~ PositiveBytes[8] # -> ""
1.01 ~~ PositiveBytes[8] # -> ""
0 ~~ PositiveBytes[8] # -> 1
my $N8 = 2 ** (8*Math::BigInt->new(8)) - 1;
$N8 . "" ~~ PositiveBytes[8] # -> 1
($N8+1) . "" ~~ PositiveBytes[8] # -> ""
-1 ~~ PositiveBytes[17] # -> ""
0 ~~ PositiveBytes[17] # -> 1
=head2 Nat
Integers 1+.
0 ~~ Nat # -> ""
1 ~~ Nat # -> 1
=head2 Ref
Link.
\1 ~~ Ref # -> 1
[] ~~ Ref # -> 1
1 ~~ Ref # -> ""
=head2 Tied`[A]
Link to the associated variable.
package TiedHash { sub TIEHASH { bless {@_}, shift } }
package TiedArray { sub TIEARRAY { bless {@_}, shift } }
package TiedScalar { sub TIESCALAR { bless {@_}, shift } }
tie my %a, "TiedHash";
tie my @a, "TiedArray";
tie my $a, "TiedScalar";
my %b; my @b; my $b;
\%a ~~ Tied # -> 1
\@a ~~ Tied # -> 1
\$a ~~ Tied # -> 1
\%b ~~ Tied # -> ""
\@b ~~ Tied # -> ""
\$b ~~ Tied # -> ""
\\$b ~~ Tied # -> ""
ref tied %a # => TiedHash
ref tied %{\%a} # => TiedHash
\%a ~~ Tied["TiedHash"] # -> 1
\@a ~~ Tied["TiedArray"] # -> 1
\$a ~~ Tied["TiedScalar"] # -> 1
\%a ~~ Tied["TiedArray"] # -> ""
\@a ~~ Tied["TiedScalar"] # -> ""
\$a ~~ Tied["TiedHash"] # -> ""
\\$a ~~ Tied["TiedScalar"] # -> ""
=head2 LValueRef
The function allows assignment.
ref \substr("abc", 1, 2) # => LVALUE
ref \vec(42, 1, 2) # => LVALUE
\substr("abc", 1, 2) ~~ LValueRef # -> 1
\vec(42, 1, 2) ~~ LValueRef # -> 1
But it doesn't work with C<:lvalue>.
sub abc: lvalue { $_ }
abc() = 12;
$_ # => 12
ref \abc() # => SCALAR
\abc() ~~ LValueRef # -> ""
package As {
sub x : lvalue {
shift->{x};
}
}
my $x = bless {}, "As";
$x->x = 10;
$x->x # => 10
$x # --> bless {x=>10}, "As"
ref \$x->x # => SCALAR
\$x->x ~~ LValueRef # -> ""
And on the end:
\1 ~~ LValueRef # -> ""
my $x = "abc";
substr($x, 1, 1) = 10;
$x # => a10c
LValueRef->include( \substr($x, 1, 1) ) # => 1
=head2 FormatRef
Format.
format EXAMPLE_FMT =
@<<<<<< @|||||| @>>>>>>
"left", "middle", "right"
.
*EXAMPLE_FMT{FORMAT} ~~ FormatRef # -> 1
\1 ~~ FormatRef # -> ""
=head2 CodeRef
Subroutine.
sub {} ~~ CodeRef # -> 1
\1 ~~ CodeRef # -> ""
=head2 NamedCode[name]
The subroutine with the specified name. C<name> â string or regular character.
sub code_ex { ... }
\&code_ex ~~ NamedCode['main::code_ex'] # -> 1
\&code_ex ~~ NamedCode['code_ex'] # -> ""
\&code_ex ~~ NamedCode[qr/_/] # -> 1
=head2 ProtoCode[prototype]
A subroutine with the specified prototype.
sub codex ($;$);
\&codex ~~ ProtoCode['@'] # -> ""
\&codex ~~ ProtoCode['$;$'] # -> 1
\&codex ~~ ProtoCode[qr/^\$/] # -> 1
=head2 ForwardRef
Subroutine without body.
sub code_ref {};
sub code_forward;
lib/Aion/Types.pm view on Meta::CPAN
File descriptor.
\*A::a ~~ FileHandle # -> ""
\*STDIN ~~ FileHandle # -> 1
open my $fh, "<", "/dev/null";
$fh ~~ FileHandle # -> 1
close $fh;
opendir my $dh, ".";
$dh ~~ FileHandle # -> 1
closedir $dh;
use constant { PF_UNIX => 1, SOCK_STREAM => 1 };
socket my $sock, PF_UNIX, SOCK_STREAM, 0;
$sock ~~ FileHandle # -> 1
close $sock;
=head2 ArrayRef`[A]
Array references.
[] ~~ ArrayRef # -> 1
{} ~~ ArrayRef # -> ""
[] ~~ ArrayRef[Num] # -> 1
{} ~~ ArrayRef[Num] # -> ''
[1, 1.1] ~~ ArrayRef[Num] # -> 1
[1, undef] ~~ ArrayRef[Num] # -> ""
=head2 Lim[A, B?]
Limits arrays from C<A> to C<B> elements, or from 0 to C<A> if C<B> is missing.
[] ~~ Lim[5] # -> 1
[1..5] ~~ Lim[5] # -> 1
[1..6] ~~ Lim[5] # -> ""
[1..5] ~~ Lim[1,5] # -> 1
[1..6] ~~ Lim[1,5] # -> ""
[1] ~~ Lim[1,5] # -> 1
[] ~~ Lim[1,5] # -> ""
=head2 HashRef`[H]
Links to hashes.
{} ~~ HashRef # -> 1
\1 ~~ HashRef # -> ""
[] ~~ HashRef[Int] # -> ""
{x=>1, y=>2} ~~ HashRef[Int] # -> 1
{x=>1, y=>""} ~~ HashRef[Int] # -> ""
=head2 Object`[O]
Blessed links.
bless(\(my $val=10), "A1") ~~ Object # -> 1
\(my $val=10) ~~ Object # -> ""
bless(\(my $val=10), "A1") ~~ Object["A1"] # -> 1
bless(\(my $val=10), "A1") ~~ Object["B1"] # -> ""
=head2 Me
Blessed references to objects of the current package.
package A1 {
use Aion;
bless({}, __PACKAGE__) ~~ Me # -> 1
bless({}, "A2") ~~ Me # -> ""
}
=head2 Map[K, V]
Like C<HashRef>, but with a key type.
{} ~~ Map[Int, Int] # -> 1
{5 => 3} ~~ Map[Int, Int] # -> 1
+{5.5 => 3} ~~ Map[Int, Int] # -> ""
{5 => 3.3} ~~ Map[Int, Int] # -> ""
{5 => 3, 6 => 7} ~~ Map[Int, Int] # -> 1
=head2 Tuple[A...]
Tuple.
["a", 12] ~~ Tuple[Str, Int] # -> 1
["a", 12, 1] ~~ Tuple[Str, Int] # -> ""
["a", 12.1] ~~ Tuple[Str, Int] # -> ""
=head2 CycleTuple[A...]
Tuple repeated one or more times.
["a", -5] ~~ CycleTuple[Str, Int] # -> 1
["a", -5, "x"] ~~ CycleTuple[Str, Int] # -> ""
["a", -5, "x", -6] ~~ CycleTuple[Str, Int] # -> 1
["a", -5, "x", -6.2] ~~ CycleTuple[Str, Int] # -> ""
=head2 Dict[k => A, ...]
Dictionary.
{a => -1.6, b => "abc"} ~~ Dict[a => Num, b => Str] # -> 1
{a => -1.6, b => "abc", c => 3} ~~ Dict[a => Num, b => Str] # -> ""
{a => -1.6} ~~ Dict[a => Num, b => Str] # -> ""
{a => -1.6} ~~ Dict[a => Num, b => Option[Str]] # -> 1
=head2 HasProp[p...]
A hash has the following properties. In addition to them, he may have others.
[0, 1] ~~ HasProp[qw/0 1/] # -> ""
{a => 1, b => 2, c => 3} ~~ HasProp[qw/a b/] # -> 1
{a => 1, b => 2} ~~ HasProp[qw/a b/] # -> 1
{a => 1, c => 3} ~~ HasProp[qw/a b/] # -> ""
bless({a => 1, b => 3}, "A") ~~ HasProp[qw/a b/] # -> 1
=head2 Like
Object or string.
"" ~~ Like # -> 1
1 ~~ Like # -> 1
bless({}, "A") ~~ Like # -> 1
bless([], "A") ~~ Like # -> 1
bless(\(my $str = ""), "A") ~~ Like # -> 1
\1 ~~ Like # -> ""
=head2 HasMethods[m...]
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 it has operators specified operators.
"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.
sub {} ~~ CodeLike # -> 1
\&CodeLike ~~ CodeLike # -> 1
{} ~~ CodeLike # -> ""
=head2 ArrayLike`[A]
Arrays or objects with an overloaded operator or C<@{}>.
{} ~~ ArrayLike # -> ""
{} ~~ ArrayLike[Int] # -> ""
[] ~~ ArrayLike # -> 1
package ArrayLikeExample {
use overload '@{}' => sub {
shift->{array} //= []
};
}
my $x = bless {}, 'ArrayLikeExample';
$x->[1] = 12;
$x->{array} # --> [undef, 12]
$x ~~ ArrayLike # -> 1
$x ~~ ArrayLike[Int] # -> ""
$x->[0] = 13;
$x ~~ ArrayLike[Int] # -> 1
=head2 HashLike`[A]
Hashes or objects with the C<%{}> operator overloaded.
{} ~~ HashLike # -> 1
[] ~~ HashLike # -> ""
[] ~~ HashLike[Int] # -> ""
package HashLikeExample {
use overload '%{}' => sub {
shift->[0] //= {}
};
}
my $x = bless [], 'HashLikeExample';
$x->{key} = 12.3;
$x->[0] # --> {key => 12.3}
$x ~~ HashLike # -> 1
$x ~~ HashLike[Int] # -> ""
$x ~~ HashLike[Num] # -> 1
=head1 Coerces
=head2 Join[R] as Str
String type with conversion of arrays to a string through a delimiter.
Join([' '])->coerce([qw/a b c/]) # => a b c
package JoinExample { use Aion;
has s => (isa => Join[', '], coerce => 1);
}
JoinExample->new(s => [qw/a b c/])->s # => a, b, c
JoinExample->new(s => 'string')->s # => string
=head2 Split[S] as ArrayRef
Split([' '])->coerce('a b c') # --> [qw/a b c/]
package SplitExample { use Aion;
has s => (isa => Split[qr/\s*,\s*/], coerce => 1);
}
SplitExample->new(s => 'a, b, c')->s # --> [qw/a b c/]
=head1 AUTHOR
Yaroslav O. Kosmina LL<mailto:dart@cpan.org>
=head1 LICENSE
â B<GPLv3>
=head1 COPYRIGHT
The Aion::Types module is copyright © 2023 Yaroslav O. Kosmina. Rusland. All rights reserved.
( run in 1.615 second using v1.01-cache-2.11-cpan-39bf76dae61 )