Aion
view release on metacpan or search on metacpan
lib/Aion/Types.pm view on Meta::CPAN
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') };
subtype "RoleName", as &PackageName, where { !$_->can('new') && !!(@{"$_\::ISA"} || first { *{$_}{CODE} } values %{"$_\::"}) };
subtype "StrRat", as &Str, where { m!\s*/\s*!? &Num->include($`) && &Num->include($`): &Num->test };
subtype "Num", as &Str, where { looks_like_number($_) && /[\dfn]\z/i };
subtype "Int", as &Num, where { /^[-+]?\d+\z/ };
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" }
lib/Aion/Types.pm view on Meta::CPAN
['+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
lib/Aion/Types.pm view on Meta::CPAN
"Hi, world!" ~~ EndsWith["world!"]; # -> 1
"Hi, world" ~~ EndsWith["world!"]; # -> ""
=head2 NonEmptyStr
A string containing one or more non-blank characters.
" " ~~ NonEmptyStr # -> ""
" S " ~~ NonEmptyStr # -> 1
" S " ~~ (NonEmptyStr & Len[2]) # -> ""
=head2 Email
Lines with C<@>.
'@' ~~ Email # -> 1
'a@a.a' ~~ Email # -> 1
'a.a' ~~ Email # -> ""
=head2 Tel
The telephone format is a plus sign and seven or more digits.
"+1234567" ~~ Tel # -> 1
"+1234568" ~~ Tel # -> 1
"+ 1234567" ~~ Tel # -> ""
"+1234567 " ~~ Tel # -> ""
=head2 Url
Website URLs are a string prefixed with http:// or https://.
"http://" ~~ Url # -> 1
"http:/" ~~ Url # -> ""
=head2 Path
Paths start with a slash.
"/" ~~ Path # -> 1
"/a/b" ~~ Path # -> 1
"a/b" ~~ Path # -> ""
=head2 Html
HTML starts with C<< E<lt>!doctype html >> or C<< E<lt>html >>.
"<HTML" ~~ Html # -> 1
" <html" ~~ Html # -> 1
" <!doctype html>" ~~ Html # -> 1
" <html1>" ~~ Html # -> ""
=head2 StrDate
Date in C<yyyy-mm-dd> format.
"2001-01-12" ~~ StrDate # -> 1
"01-01-01" ~~ StrDate # -> ""
=head2 StrDateTime
Date and time in the format C<yyyy-mm-dd HH:MM:SS>.
"2012-12-01 00:00:00" ~~ StrDateTime # -> 1
"2012-12-01 00:00:00 " ~~ StrDateTime # -> ""
=head2 StrMatch[regexp]
Matches a string against a regular expression.
' abc ' ~~ StrMatch[qr/abc/] # -> 1
' abbc ' ~~ StrMatch[qr/abc/] # -> ""
=head2 ClassName
The class name is a package with a C<new> method.
'Aion::Type' ~~ ClassName # -> 1
'Aion::Types' ~~ ClassName # -> ""
=head2 RoleName
The role name is a package without the C<new> method, with C<@ISA>, or with any one method.
package ExRole1 {
sub any_method {}
}
package ExRole2 {
our @ISA = qw/ExRole1/;
}
'ExRole1' ~~ RoleName # -> 1
'ExRole2' ~~ RoleName # -> 1
'Aion::Type' ~~ RoleName # -> ""
'Nouname::Empty::Package' ~~ RoleName # -> ""
=head2 StrRat
String representation of rational numbers.
Since in perl rational numbers are supported using the C<bigrat> pragma, which turns all rational numbers into C<Math::BigRat>, it is used in a ghost to C<Rat>.
"6/7" ~~ StrRat # -> 1
"-6/7" ~~ StrRat # -> 1
"+6/7" ~~ StrRat # -> 1
6 ~~ StrRat # -> 1
"inf" ~~ StrRat # -> 1
"+Inf" ~~ StrRat # -> 1
"NaN" ~~ StrRat # -> 1
"-nan" ~~ StrRat # -> 1
6.5 ~~ StrRat # -> 1
"6.5 " ~~ StrRat # -> ''
=head2 Rat
Rational numbers. Short for C<Object['Math::BigRat']>. Has a ghost.
use Math::BigRat;
use Math::BigFloat;
use Math::BigInt;
"6/7" ~~ Rat # -> ""
Math::BigRat->new("6/7") ~~ Rat # -> 1
( run in 0.747 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )