Aion

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN


## pleroma ()

Возвращает локатор.

```perl
Aion->pleroma->isa('Aion::Pleroma')  # -> 1
```

# SUBROUTINES IN CLASSES

## extends (@superclasses)

Расширяет класс другим классом/классами. Он вызывает из каждого наследуемого класса метод `import_extends`, если он в нём есть.

```perl
package World { use Aion;

	our $extended_by_this = 0;

	sub import_extends {
		my ($class, $extends) = @_;
		$extended_by_this ++;

		$class   # => World
		$extends # => Hello
	}
}

package Hello { use Aion;
	extends q/World/;

	$World::extended_by_this # -> 1
}

Hello->isa("World")	 # -> 1
```

## new (%param)

Конструктор.

* Устанавливает `%param` для фич.
* Проверяет, что параметры соответствуют фичам.
* Устанавливает значения по умолчанию.

```perl
package NewExample { use Aion;
	has x => (is => 'ro', isa => Num);
	has y => (is => 'ro+', isa => Num);
	has z => (is => 'ro-', isa => Num);
}

NewExample->new(f => 5) # @-> y required!
NewExample->new(f => 5, y => 10) # @-> f is'nt feature!
NewExample->new(f => 5, p => 6, y => 10) # @-> f, p is'nt features!
NewExample->new(z => 10, y => 10) # @-> z excessive!

my $ex = NewExample->new(y => 8);

$ex->x # @-> Get feature x must have the type Num. The it is undef!

$ex = NewExample->new(x => 10.1, y => 8);

$ex->x # -> 10.1
```

# SUBROUTINES IN ROLES

## requires (@subroutine_names)

Проверяет, что в классах, использующих эту роль, есть указанные подпрограммы или фичи.

```perl
package Role::Alpha { use Aion -role;

	requires qw/abc/;
}

package Omega1 { use Aion; with Role::Alpha; }

eval { Omega1->new }; $@ # ~> Requires abc of Role::Alpha

package Omega { use Aion;
	with Role::Alpha;

	sub abc { "abc" }
}

Omega->new->abc  # => abc
```

## req ($name => @aspects)

Проверяет, что в классах, использующих эту роль, есть указанные фичи с указанными аспектами.

```perl
package Role::Beta { use Aion -role;

	req x => (is => 'rw', isa => Num);
}

package Omega2 { use Aion; with Role::Beta; }

eval { Omega2->new }; $@ # ~> Requires req x => \(is => 'rw', isa => Num\) of Role::Beta

package Omega3 { use Aion;
	with Role::Beta;

	has x => (is => 'rw', isa => Num, default => 12);
}

Omega3->new->x  # -> 12
```

## Роль наследует роль

Роль может наследовать другую роль через `with`. Так можно уточнять интерфейс: типы требующихся фичей (`req`) и методов (`:Isa`) либо остаются такÐ...

Роль `Role::Animal` требует свойство `legs` широкого типа `Num | Object` и метод `sound` с сигнатурой `(Me => Str)`.

README.md  view on Meta::CPAN


	Num < (Num | Object)  # -> 1
}

my $sparrow = Ex::Sparrow->new;
$sparrow->legs  # => 2
$sparrow->sound # => chirp
```

# ASPECTS

`use Aion` включает в модуль следующие аспекты для использования в `has`:

## is => $permissions

* `ro` — создать только геттер.
* `wo` — создать только сеттер.
* `rw` — создать геттер и сеттер.

По умолчанию — `rw`.

Дополнительные разрешения:

* `+` — фича обязательна в параметрах конструктора. `+` не используется с `-`.
* `-` — фича не может быть установлена через конструктор. '-' не используется с `+`.
* `*` — не инкрементировать счётчик ссылок на значение (применить `weaken` к значению после установки его в фичу).
* `?` – создать предикат.
* `!` – создать clearer.

```perl
package ExIs { use Aion;
	has rw => (is => 'rw?!');
	has ro => (is => 'ro+');
	has wo => (is => 'wo-?');
}

ExIs->new # @-> ro required!
ExIs->new(ro => 10, wo => -10) # @-> wo excessive!

ExIs->new(ro => 10)->has_rw # -> ""
ExIs->new(ro => 10, rw => 20)->has_rw # -> 1
ExIs->new(ro => 10, rw => 20)->clear_rw->has_rw # -> ""

ExIs->new(ro => 10)->ro  # -> 10

ExIs->new(ro => 10)->wo(30)->has_wo # -> 1
ExIs->new(ro => 10)->wo # @-> Feature wo cannot be get!
ExIs->new(ro => 10)->rw(30)->rw  # -> 30
```

Функция с `*` не удерживает значение:

```perl
package Node { use Aion;
	has parent => (is => "rw*", isa => Maybe[Object["Node"]]);
}

my $root = Node->new;
my $node = Node->new(parent => $root);

$node->parent->parent   # -> undef
undef $root;
$node->parent   # -> undef

# And by setter:
$node->parent($root = Node->new);

$node->parent->parent   # -> undef
undef $root;
$node->parent   # -> undef
```

## isa => $type

Указывает тип, а точнее – валидатор, фичи.

Может принимать:

* `Aion::Type` – Aion сразу импортирует в пакет все типы из [Aion::Types](https://metacpan.org/pod/Aion::Types).
* Строки воспримаются как пакеты и оборачиваются в `Object`.
* Подпрограммы – тестируемое значение передаётся в `$_` и подпрограмма возвращает булево значение.
* Объекты с перегруженным оператором `&{}`. Если у такого объекта есть ещё и метод `coerce`, то он будет учавствовать в приведениях, если указатÑ...

```perl
package Externalis {
	use overload '&{}' => sub { sub { /^\d+$/ } };
	sub coerce { int $_ }
}

package ExIsa { use Aion;
	has x => (isa => Int);
	has y => (isa => sub { /^\d+$/ });
	has z => (isa => bless({}, 'Externalis'), coerce => 1);
}

ExIsa->new(x => 'str') # @-> Set feature x must have the type Int. The it is 'str'!
ExIsa->new->x # @-> Get feature x must have the type Int. The it is undef!
ExIsa->new(x => 10)->x			  # -> 10

ExIsa->new(y => 'abc') # @-> Set feature y must have the type External[CODE
ExIsa->new(z => ' 6 xyz')->z # -> 6
```

## coerce => (1|0)

Включает преобразования типов.

```perl
package ExCoerce { use Aion;
	has x => (is => 'ro', isa => Int, coerce => 1);
}

ExCoerce->new(x => 10.4)->x  # -> 10
ExCoerce->new(x => 10.5)->x  # -> 11
```

## default => $value

Значение по умолчанию устанавливается в конструкторе, если параметр с именем фичи отсутствует.

```perl
package ExDefault { use Aion;
	has x => (is => 'ro', default => 10);
}

ExDefault->new->x  # -> 10
ExDefault->new(x => 20)->x  # -> 20
```

Если `$value` является подпрограммой, то подпрограмма считается конструктором значения фичи. Используется ленивое вычисление, если нет атр...

```perl
my $count = 10;

package ExLazy { use Aion;
	has x => (default => sub {
		my ($self) = @_;
		++$count
	});
}

my $ex = ExLazy->new;
$count   # -> 10
$ex->x   # -> 11
$count   # -> 11
$ex->x   # -> 11
$count   # -> 11
```

## lazy => (1|0)

Аспект `lazy` включает или отключает ленивое вычисление значения по умолчанию (`default`).

По умолчанию он включен только если значение по умолчанию является подпрограммой.

```perl
package ExLazy0 { use Aion;

README.md  view on Meta::CPAN

package ExLazy1 { use Aion;
	has x => (is => 'ro?', lazy => 1, default => 6);
}

my $ex1 = ExLazy1->new;
$ex1->has_x # -> ""
$ex1->x     # -> 6
```

## eon => (1|2|$key)

С помощью аспекта `eon` реализуется паттерн **Dependency Injection**.

Он связывает свойство с сервисом из контейнера `Aion->pleroma`.

Значением аспекта может быть ключ сервиса, 1 или 2.

* Если 1 – тогда ключём будет пакет в `isa => Object['Packet']`.
* Если 2 – тогда ключём будет "пакет#свойство".

Файл lib/CounterEon.pm:
```perl
package CounterEon;
#@eon ex.counter
use Aion;

has accomulator => (isa => 'AccomulatorEon', eon => 1);

1;
```

Файл lib/AccomulatorEon.pm:
```perl
package AccomulatorEon;
#@eon
use Aion;

has power => (isa => 'PowerEon', eon => 2);

1;
```

Файл lib/PowerEon.pm:
```perl
package PowerEon;
use Aion;

has counter => (eon => 'ex.counter');
	
#@eon
sub power { shift->new }

1;
```

Используем плерому локально:

```perl
{
	use Aion::Pleroma;
	my $pleroma = Aion::Pleroma->new(ini => undef, pleroma => {
		'ex.counter' => 'CounterEon#new',
		AccomulatorEon => 'AccomulatorEon#new',
		'PowerEon#power' => 'PowerEon#power',
	});

	local *Aion::pleroma = sub { $pleroma };
	
	my $counter = Aion->pleroma->get('ex.counter');

	$counter->accomulator->power->counter # -> $counter
}

Aion->pleroma->get('ex.counter') # -> undef
```

См. [Aion::Pleroma](https://metacpan.org/pod/Aion::Pleroma).

## trigger => $sub

`$sub` вызывается после установки свойства в конструкторе (`new`) или через сеттер.

Этимология `trigger` – впустить.

```perl
package ExTrigger { use Aion;
	has x => (trigger => sub {
		my ($self, $old_value) = @_;
		$self->y($old_value + $self->x);
	});

	has y => ();
}

my $ex = ExTrigger->new(x => 10);
$ex->y	  # -> 10
$ex->x(20);
$ex->y	  # -> 30
```

## release => $sub

`$sub` вызывается перед возвратом свойства из объекта через геттер.

Этимология `release` – выпустить.

```perl
package ExRelease { use Aion;
	has x => (release => sub {
		my ($self, $value) = @_;
		$_[1] = $value + 1;
	});
}

my $ex = ExRelease->new(x => 10);
$ex->x	  # -> 11
```

## init_arg => $name

Меняет имя свойства в конструкторе.

```perl
package ExInitArg { use Aion;
	has x => (is => 'ro+', init_arg => 'init_x');

	ExInitArg->new(init_x => 10)->x # -> 10
}
```

## accessor => $name

Меняет имя акцессора.

README.md  view on Meta::CPAN

Создаёт геттер с именем `$name` для свойства.

```perl
package ExReader { use Aion;
	has x => (is => 'wo', reader => '_get_x');

	ExReader->new(x => 10)->_get_x # -> 10
}
```

## predicate => $name

Создаёт предикат с именем `$name` для свойства. Создать предикат со стандартным именем можно так же через  `is => '?'`.

```perl
package ExPredicate { use Aion;
	has x => (predicate => '_has_x');
	
	my $ex = ExPredicate->new;
	$ex->_has_x        # -> ""
	$ex->x(10)->_has_x # -> 1
}
```

## clearer => $name

Создаёт очиститель с именем `$name` для свойства. Создать очиститель со стандартным именем можно так же через  `is => '!'`.

```perl
package ExClearer { use Aion;
	has x => (is => '?', clearer => 'clear_x_');
}

my $ex = ExClearer->new;
$ex->has_x	  # -> ""
$ex->clear_x_;
$ex->has_x	  # -> ""
$ex->x(10);
$ex->has_x	  # -> 1
$ex->clear_x_;
$ex->has_x	  # -> ""
```

## cleaner => $sub

`$sub` вызывается при вызове декструктора или `$object->clear_feature`, но только если свойство имеется (см. `$object->has_feature`).

Данный аспект принудительно создаёт предикат и clearer.

```perl
package ExCleaner { use Aion;

	our $x;

	has x => (is => '!', cleaner => sub {
		my ($self) = @_;
		$x = $self->x
	});
}

$ExCleaner::x		  # -> undef
ExCleaner->new(x => 10);
$ExCleaner::x		  # -> 10

my $ex = ExCleaner->new(x => 12);

$ExCleaner::x	  # -> 10
$ex->clear_x;
$ExCleaner::x	  # -> 12

undef $ex;

$ExCleaner::x	  # -> 12
```

# ATTRIBUTES

`Aion` добавляет в пакет универсальные атрибуты.

## :Isa (@signature)

Атрибут `Isa` проверяет сигнатуру функции.

```perl
package MaybeCat { use Aion;

	sub is_cat : Isa(Me => Str => Bool) {
		my ($self, $anim) = @_;
		$anim =~ /(cat)/
	}
}

my $anim = MaybeCat->new;
$anim->is_cat('cat')	# -> 1
$anim->is_cat('dog')	# -> ""

MaybeCat->is_cat("cat") # @-> Arguments of method `is_cat` must have the type Tuple[Me, Str].
my @items = $anim->is_cat("cat") # @-> Returns of method `is_cat` must have the type Tuple[Bool].
```

Атрибут Isa позволяет объявить требуемые функции:

```perl
package Anim { use Aion -role;

	sub is_cat : Isa(Me => Bool);
}

package Cat { use Aion; with qw/Anim/;

	sub is_cat : Isa(Me => Bool) { 1 }
}

package Dog { use Aion; with qw/Anim/;

	sub is_cat : Isa(Me => Bool) { 0 }
}

package Mouse { use Aion; with qw/Anim/;
	
	sub is_cat : Isa(Me => Int) { 0 }
}

Cat->new->is_cat # -> 1
Dog->new->is_cat # -> 0
Mouse->new # @-> Signature mismatch: is_cat(Me => Bool) of Anim <=> is_cat(Me => Int) of Mouse
```

# SEE ALSO

Экосистема Aion:



( run in 1.347 second using v1.01-cache-2.11-cpan-d80b1682f3f )