Aion
view release on metacpan or search on metacpan
lib/Aion/Types.pm view on Meta::CPAN
$awhere? (a_test => $awhere): (),
$message? (message => $message): (),
);
if($is_maybe_arg) {
$type->make_maybe_arg($pkg)
} elsif($is_arg || @init) {
$type->make_arg($pkg, $is_arg)
} else {
$type->make($pkg)
}
}
}
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 };
lib/Aion/Types.pm view on Meta::CPAN
}
"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+$_ };
Four->coerce("4a") # -> 4
coerce Four, from ArrayRef, via { scalar @$_ };
Four->coerce([1,2,3]) # -> 3
Four->coerce([1,2,3]) ~~ Four # -> ""
Four->coerce([1,2,3,4]) ~~ Four # -> 1
Can use parameters like:
BEGIN {
subtype 'Plus[acc]', as Num;
}
coerce &Plus, from Num, via { $_ + A };
Plus([5])->coerce(4) # -> 9
Plus([5]) >> 5 # -> 10
1 >> Plus[5] # -> 6
C<coerce> throws exceptions:
eval {coerce Int, via1 => 1}; $@ # ~> coerce Int unused keys left: via1
eval {coerce "x"}; $@ # ~> coerce x not Aion::Type!
eval {coerce Int}; $@ # ~> coerce Int: from is'nt Aion::Type!
eval {coerce Int, from "x"}; $@ # ~> coerce Int: from is'nt Aion::Type!
eval {coerce Int, from Num}; $@ # ~> coerce Int: via is not subroutine!
eval {coerce Int, (from=>Num, via=>"x")}; $@ # ~> coerce Int: via is not subroutine!
Standard casts:
# Str from Undef â empty string
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...]
lib/Aion/Types.pm view on Meta::CPAN
=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($_): $_ }
}
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]; # -> ""
Enum["cat"] <= Enum["cat", "dog"] # -> 1
Enum["cat", "dog"] <= Enum["cat", "dog"] # -> 1
Enum(["cat", "dog"])->disjoint(Enum[1]) # -> 1
Enum(["cat", "dog"])->disjoint(Enum["ret", "cat"]) # -> ""
Enum[1,2] <= Enum[1,2,3] # -> 1
Enum[1,2] <= Enum[2,3] # -> ""
Enum[1,2] == Enum[2,1] # -> 1
Enum[1,2] < Enum[1,2,3] # -> 1
Enum[1,2,3] > Enum[1,2] # -> 1
Enum[1,2] == (Enum[1] | Enum[2]) # -> 1
=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> or 0 to C<to>.
"1234" ~~ Len[3] # -> ""
"123" ~~ Len[3] # -> 1
"12" ~~ Len[3] # -> 1
"" ~~ Len[1, 2] # -> ""
"1" ~~ Len[1, 2] # -> 1
"12" ~~ Len[1, 2] # -> 1
"123" ~~ Len[1, 2] # -> ""
Len[3] <= Len[3] # -> 1
Len[3] <= Len[4] # -> 1
Len[3] <= Len[2] # -> ""
=head2 Version
Perl version.
1.1.0 ~~ Version # -> 1
1.1.0.5 ~~ Version # -> 1
v1.1.0 ~~ Version # -> 1
v1.1 ~~ Version # -> 1
v1 ~~ Version # -> 1
1.1 ~~ Version # -> ""
"1.1.0" ~~ Version # -> ""
=head2 Str
Strings, including numbers.
1.1 ~~ Str # -> 1
"" ~~ Str # -> 1
1.1.0 ~~ Str # -> ""
=head2 Uni
Unicode strings with the utf8 flag or if decoding to utf8 occurs without errors.
"â" ~~ Uni # -> 1
123 ~~ Uni # -> ""
do {no utf8; "â" ~~ Uni} # -> 1
=head2 Bin
Binary strings without the utf8 flag and octets with numbers less than 128.
123 ~~ Bin # -> 1
"z" ~~ Bin # -> 1
"â" ~~ Bin # -> ""
do {no utf8; "â" ~~ Bin } # -> ""
=head2 StartsWith[begin]
The line starts with C<begin>.
"Hi, world!" ~~ StartsWith["Hi,"]; # -> 1
"Hi world!" ~~ StartsWith["Hi,"]; # -> ""
lib/Aion/Types.pm view on Meta::CPAN
\12 ~~ ValueRef # -> 1
\12 ~~ ValueRef # -> 1
\-1.2 ~~ ValueRef[Num] # -> 1
\\-1.2 ~~ ValueRef[ValueRef[Num]] # -> 1
=head2 ScalarRef`[A]
Reference to a scalar.
\12 ~~ ScalarRef # -> 1
\\12 ~~ ScalarRef # -> ""
\-1.2 ~~ ScalarRef[Num] # -> 1
=head2 RefRef`[A]
Link to link.
\12 ~~ RefRef # -> ""
\\12 ~~ RefRef # -> 1
\-1.2 ~~ RefRef[Num] # -> ""
\\-1.2 ~~ RefRef[ScalarRef[Num]] # -> 1
=head2 GlobRef
Link to global
\*A::a ~~ GlobRef # -> 1
*A::a ~~ GlobRef # -> ""
=head2 FileHandle
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[from?, to]
Limits arrays from C<from> or 0 to C<to> elements.
[] ~~ 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] # -> ""
Lim[0, 10] <= Lim[0, 20] # -> 1
Lim[10, 'Inf'] <= Lim[0, 'Inf'] # -> 1
Lim[3] <= Lim[5] # -> 1
Lim[3] <= Lim[2] # -> ""
Lim[2,5] < Lim[1,6] # -> 1
Lim[2,5] == Lim[2,5] # -> 1
=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
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.
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>
( run in 1.526 second using v1.01-cache-2.11-cpan-d80b1682f3f )