Aion

 view release on metacpan or  search on metacpan

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

						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

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

								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>.

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


	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;
	
	\&code_forward ~~ ForwardRef # -> 1
	\&code_ref ~~ ForwardRef     # -> ""

A subroutine without a body is usually used for pre-declaration, but XS functions also have no body:

	\&UNIVERSAL::isa ~~ ForwardRef # -> 1

Calling an undeclared function using C<\&> creates a reference to the previously declared function:

	main->can('nouname') ~~ ForwardRef # -> ""
	
	\&nouname ~~ ForwardRef # -> 1
	
	main->can('nouname') ~~ ForwardRef # -> 1

=head2 ImplementRef

Subroutine with body.

	sub code_ref {};
	sub code_forward;
	
	\&code_ref ~~ ImplementRef     # -> 1
	\&code_forward ~~ ImplementRef # -> ""

=head2 Isa[A...]

A link to a subroutine with the corresponding signature.

	sub sig_ex :Isa(Aion => Int => Str) {}
	
	\&sig_ex ~~ Isa[Aion => Int => Str] # -> 1
	\&sig_ex ~~ Isa[Object['Aion'] => Int => Str] # -> 1
	\&sig_ex ~~ Isa[Aion => Str => Num] # -> ""
	\&sig_ex ~~ Isa[Int => Num] # -> ""

Subroutines without a body are not wrapped in a signature handler, and the signature is remembered to validate the conformity of a subsequently declared subroutine with a body. Therefore the function has no signature.

	sub unreachable_sig_ex :Isa(Int => Str);
	
	\&unreachable_sig_ex ~~ Isa[Int => Str] # -> ""

=head2 RegexpRef

Regular expression.

	qr// ~~ RegexpRef # -> 1
	\1 ~~ RegexpRef   # -> ""

=head2 ValueRef`[A]

A reference to a scalar or reference.

	\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;
	



( run in 2.658 seconds using v1.01-cache-2.11-cpan-d01c6094234 )