Aion

 view release on metacpan or  search on metacpan

t/aion/type.t  view on Meta::CPAN

use common::sense; use open qw/:std :utf8/;  use Carp qw//; use Cwd qw//; use File::Basename qw//; use File::Find qw//; use File::Slurper qw//; use File::Spec qw//; use File::Path qw//; use Scalar::Util qw//;  use Test::More 0.98;  use String::Diff q...
# # NAME
# 
# Aion::Type - класс валидаторов
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
use Aion::Type;
use Aion::Types qw//;

my $Int = Aion::Type->new(name => "Int", test => sub { /^-?\d+$/ });
local ($::_g0 = do {12   ~~ $Int}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '12   ~~ $Int # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {12.1 ~~ $Int}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '12.1 ~~ $Int # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

my $Char = Aion::Type->new(name => "Char", test => sub { /^.\z/ });
local ($::_g0 = do {$Char->include("a")}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '$Char->include("a")	 # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$Char->exclude("ab")}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '$Char->exclude("ab") # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

my $IntOrChar = $Int | $Char;
local ($::_g0 = do {77   ~~ $IntOrChar}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '77   ~~ $IntOrChar # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {"a"  ~~ $IntOrChar}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '"a"  ~~ $IntOrChar # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {"ab" ~~ $IntOrChar}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '"ab" ~~ $IntOrChar # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

my $Digit = $Int & $Char;
local ($::_g0 = do {7  ~~ $Digit}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '7  ~~ $Digit # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {77 ~~ $Digit}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '77 ~~ $Digit # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

local ($::_g0 = do {"a" ~~ ~$Int;}, $::_e0 = "1"); ::ok $::_g0 eq $::_e0, '"a" ~~ ~$Int; # => 1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {5   ~~ ~$Int;}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '5   ~~ ~$Int; # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

::like scalar do {eval { $Int->validate("a", "..Eval..") }; $@}, qr{..Eval.. must have the type Int. The it is 'a'}, 'eval { $Int->validate("a", "..Eval..") }; $@ # ~> ..Eval.. must have the type Int. The it is \'a\''; undef $::_g0; undef $::_e0;

# 
# # DESCRIPTION
# 
# Порождает валидаторы. Используется в `Aion::Types::subtype`.
# 
# # METHODS
# 
# ## new (%ARGUMENTS)
# 
# Конструктор.
# 
# ### ARGUMENTS
# 
# * name (Str) — Название типа.
# * args (ArrayRef) — Список аргументов типа.
# * init (CodeRef) — Инициализатор типа.
# * test (CodeRef) — Чекер.
# * a_test (CodeRef) — Чекер значений для типов с необязательными аргументами.
# * coerce (ArrayRef[Tuple[Aion::Type, CodeRef]]) — Массив пар: тип и переход.
# 
# ## stringify
# 
# Строковое преобразование объекта (имя с аргументами):
# 
::done_testing; }; subtest 'stringify' => sub { 
my $Char = Aion::Type->new(name => "Char");

local ($::_g0 = do {$Char->stringify}, $::_e0 = "Char"); ::ok $::_g0 eq $::_e0, '$Char->stringify # => Char' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

my $Int = Aion::Type->new(
	name => "Int",
	args => [3, 5],
);

local ($::_g0 = do {$Int->stringify}, $::_e0 = "Int[3, 5]"); ::ok $::_g0 eq $::_e0, '$Int->stringify  #=> Int[3, 5]' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# Операции так же преобразуются в строку:
# 

local ($::_g0 = do {($Int & $Char)->stringify}, $::_e0 = "( Int[3, 5] & Char )"); ::ok $::_g0 eq $::_e0, '($Int & $Char)->stringify   # => ( Int[3, 5] & Char )' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {($Int | $Char)->stringify}, $::_e0 = "( Int[3, 5] | Char )"); ::ok $::_g0 eq $::_e0, '($Int | $Char)->stringify   # => ( Int[3, 5] | Char )' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {(~$Int)->stringify}, $::_e0 = "~Int[3, 5]"); ::ok $::_g0 eq $::_e0, '(~$Int)->stringify		  # => ~Int[3, 5]' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# Операции — это объекты `Aion::Type` со специальными именами:
# 

local ($::_g0 = do {Aion::Type->new(name => "Exclude", args => [$Char])->stringify}, $::_e0 = "~Char"); ::ok $::_g0 eq $::_e0, 'Aion::Type->new(name => "Exclude", args => [$Char])->stringify   # => ~Char' or ::diag ::_string_diff($::_g0, $::_e0); und...
local ($::_g0 = do {Aion::Type->new(name => "Union", args => [$Int, $Char])->stringify}, $::_e0 = "( Int[3, 5] | Char )"); ::ok $::_g0 eq $::_e0, 'Aion::Type->new(name => "Union", args => [$Int, $Char])->stringify   # => ( Int[3, 5] | Char )' or ::di...
local ($::_g0 = do {Aion::Type->new(name => "Intersection", args => [$Int, $Char])->stringify}, $::_e0 = "( Int[3, 5] & Char )"); ::ok $::_g0 eq $::_e0, 'Aion::Type->new(name => "Intersection", args => [$Int, $Char])->stringify   # => ( Int[3, 5] & C...

# 
# ## test
# 
# Тестирует, что `$_` принадлежит классу.
# 
::done_testing; }; subtest 'test' => sub { 
my $PositiveInt = Aion::Type->new(

t/aion/type.t  view on Meta::CPAN

# 
::done_testing; }; subtest 'include ($element)' => sub { 
my $PositiveInt = Aion::Type->new(
	name => "PositiveInt",
	test => sub { /^\d+$/ },
);

local ($::_g0 = do {$PositiveInt->include(5)}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$PositiveInt->include(5) # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$PositiveInt->include(-6)}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$PositiveInt->include(-6) # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## exclude ($element)
# 
# Проверяет, что аргумент не принадлежит классу.
# 
::done_testing; }; subtest 'exclude ($element)' => sub { 
my $PositiveInt = Aion::Type->new(
	name => "PositiveInt",
	test => sub { /^\d+$/ },
);

local ($::_g0 = do {$PositiveInt->exclude(5)}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$PositiveInt->exclude(5)  # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$PositiveInt->exclude(-6)}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$PositiveInt->exclude(-6) # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## coerce ($value)
# 
# Привести `$value` к типу, если приведение из типа и функции находится в `$self->{coerce}`.
# 
# Соответствует оператору `>>`.
# 
::done_testing; }; subtest 'coerce ($value)' => sub { 
my $Int = Aion::Type->new(name => "Int", test => sub { /^-?\d+\z/ });
my $Num = Aion::Type->new(name => "Num", test => sub { /^-?\d+(\.\d+)?\z/ });
my $Bool = Aion::Type->new(name => "Bool", test => sub { /^(1|0|)\z/ });

push @{$Int->{coerce}}, [$Bool, sub { 0+$_ }];
push @{$Int->{coerce}}, [$Num, sub { int($_+.5) }];

local ($::_g0 = do {$Int->coerce(5.5)}, $::_e0 = "6"); ::ok $::_g0 eq $::_e0, '$Int->coerce(5.5)	 # => 6' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$Int->coerce(undef)}, $::_e0 = "0"); ::ok $::_g0 eq $::_e0, '$Int->coerce(undef)  # => 0' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$Int->coerce("abc")}, $::_e0 = "abc"); ::ok $::_g0 eq $::_e0, '$Int->coerce("abc")  # => abc' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## detail ($element, $feature)
# 
# Формирует сообщение ошибки.
# 
::done_testing; }; subtest 'detail ($element, $feature)' => sub { 
my $Int = Aion::Type->new(name => "Int");

local ($::_g0 = do {$Int->detail(-5, "Feature car")}, $::_e0 = "Feature car must have the type Int. The it is -5!"); ::ok $::_g0 eq $::_e0, '$Int->detail(-5, "Feature car") # => Feature car must have the type Int. The it is -5!' or ::diag ::_string_d...

my $Num = Aion::Type->new(name => "Num", message => sub {
	"Error: $_ is'nt $Aion::Type::SELF->{property}!"
});

local ($::_g0 = do {$Num->detail("x", "car")}, $::_e0 = "Error: x is'nt car!"); ::ok $::_g0 eq $::_e0, '$Num->detail("x", "car") # => Error: x is\'nt car!' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## validate ($element, $feature)
# 
# Проверяет `$element` и выбрасывает сообщение `detail`, если элемент не принадлежит классу.
# 
::done_testing; }; subtest 'validate ($element, $feature)' => sub { 
my $PositiveInt = Aion::Type->new(
	name => "PositiveInt",
	test => sub { /^\d+$/ },
);

eval {
	$PositiveInt->validate(-1, "Neg")
};
::like scalar do {$@}, qr{Neg must have the type PositiveInt. The it is -1}, '$@ # ~> Neg must have the type PositiveInt. The it is -1'; undef $::_g0; undef $::_e0;

# 
# ## val_to_str ($val)
# 
# Переводит `$val` в строку.
# 
::done_testing; }; subtest 'val_to_str ($val)' => sub { 
local ($::_g0 = do {Aion::Type->new->val_to_str([1,2,{x=>6}])}, $::_e0 = "[1, 2, {x => 6}]"); ::ok $::_g0 eq $::_e0, 'Aion::Type->new->val_to_str([1,2,{x=>6}]) # => [1, 2, {x => 6}]' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e...

# 
# ## instanceof ($type)
# 
# Определяет, что тип является подтипом другого `$type` по имени типа.
# 
# В `|` и `~` не заходит. Аргументы не проверяет.
# 
::done_testing; }; subtest 'instanceof ($type)' => sub { 
my $Int = Aion::Type->new(name => "Int");
my $PositiveInt = Aion::Type->new(name => "PositiveInt", as => $Int);

local ($::_g0 = do {$PositiveInt->instanceof('Int');}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$PositiveInt->instanceof(\'Int\');          # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $...
local ($::_g0 = do {$PositiveInt->instanceof('PositiveInt');}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$PositiveInt->instanceof(\'PositiveInt\');  # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0;...
local ($::_g0 = do {$Int->instanceof('PositiveInt');}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$Int->instanceof(\'PositiveInt\');          # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef...

my $MyEnum = Aion::Type->new(name => "MyEnum", args => [3, 5, 'car']);
local ($::_g0 = do {($MyEnum & $PositiveInt)->instanceof('Int');}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '($MyEnum & $PositiveInt)->instanceof(\'Int\'); # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef ...

# 
# ## is_set_theoretic
# 
# Проверяет, что тип является множественно-теоритическим (т.е. – оператором `|`, `&` или `~`).
# 
# ## simplify
# 
# Если выражение не имеет значений – вернёт `~Any`, иначе – выражение.
# 
# Упрощение выражения в этой функции возможно появится в будущем.
# 
::done_testing; }; subtest 'simplify' => sub { 
package Aion::Types;

my $type = (Enum[1,2] | Enum[2,3]) & Enum[2,3,4];

local ($::_g0 = do {$type->simplify->stringify}, $::_e0 = "( ( Enum[1, 2] | Enum[2, 3] ) & Enum[2, 3, 4] )"); ::ok $::_g0 eq $::_e0, '$type->simplify->stringify # => ( ( Enum[1, 2] | Enum[2, 3] ) & Enum[2, 3, 4] )' or ::diag ::_string_diff($::_g0, $:...

my $range = Range[-10,0] & Range[4,8];
local ($::_g0 = do {$range->simplify->stringify}, $::_e0 = "~Any"); ::ok $::_g0 eq $::_e0, '$range->simplify->stringify # => ~Any' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## Any
# 
# Константа для типа включающего все значения.
# 
::done_testing; }; subtest 'Any' => sub { 
package Aion::Type;

local ($::_g0 = do {42 ~~ Any}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '42 ~~ Any   # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {42 ~~ None}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '42 ~~ None  # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;



( run in 1.423 second using v1.01-cache-2.11-cpan-d01c6094234 )