Aion

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

	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)

README.md  view on Meta::CPAN

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

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

README.md  view on Meta::CPAN

	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)

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

README.md  view on Meta::CPAN

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` – впустить.

README.md  view on Meta::CPAN

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)

i18n/Aion/Env.ru-en.po  view on Meta::CPAN

msgid "Aion::Env - создаёт константу связанную со значением из .env"
msgstr "Aion::Env - creates a constant associated with the value from .env"

msgid "Файл .env:"
msgstr ".env file:"

msgid "В проектах используется конфигурационный файл `.env` для конфигурации проекта, в `Makefile`, для `docker` и `docker compose`. Данный модуль позволяет оф...
msgstr "Projects use the `.env` configuration file for project configuration, in `Makefile`, for `docker` and `docker compose`. This module allows you to design environment variables as constants of `perl` modules."

msgid "Константы инициализируются из `%ENV`, если там нет значения или оно `undef`, то из файла `.env`, а если и там его не будет – из опции `default`."
msgstr "Constants are initialized from `%ENV`, if there is no value there or it is `undef`, then from the `.env` file, and if it is not there, from the `default` option."

msgid "При парсинге файла, ошибка синтаксиса приведёт к исключению."
msgstr "When parsing a file, a syntax error will result in an exception."

msgid "Тип переменной окружения можно проверять с помощью опции `isa`."
msgstr "The type of an environment variable can be checked using the `isa` option."

msgid "Рекомендуется называть переменные окружения используя название модуля в котором она объявлена. Например, пакет `Aion::Type`, тогда имена ...
msgstr "It is recommended to name environment variables using the name of the module in which it is declared. For example, the package is `Aion::Type`, then the names of the environment variables in it are `AION_TYPE_*`."

i18n/Aion/Meta/Feature.ru-en.po  view on Meta::CPAN

"Ограничение типа для значения фичи."
msgstr "## isa (;Object[Aion::Type])\n"
"Type constraint on feature value."

msgid "## lazy (;$bool)\n"
"Флаг ленивой инициализации."
msgstr "## lazy (;$bool)\n"
"Lazy initialization flag."

msgid "## builder (;$sub)\n"
"Билдер значения фичи или `undef`."
msgstr "## builder (;$sub)\n"
"Feature value builder or `undef`."

msgid "## default (;$value)\n"
"Значение по умолчанию для фичи."
msgstr "## default (;$value)\n"
"Default value for the feature."

msgid "## trigger (;$sub)\n"
"Обработчик события изменения значения фичи или `undef`."
msgstr "## trigger (;$sub)\n"
"Event handler for feature value change or `undef`."

msgid "## release (;$sub)\n"
"Обработчик события чтения значения из фичи или `undef`."
msgstr "## release (;$sub)\n"
"Event handler for reading a value from a feature or `undef`."

msgid "## cleaner (;$sub)\n"
"Обработчик события удаления фичи из объекта или `undef`."
msgstr "## cleaner (;$sub)\n"
"Event handler for removing a feature from an object or `undef`."

msgid "## make_reader (;$bool)\n"
"Флаг создания метода-ридера."
msgstr "## make_reader (;$bool)\n"
"Flag for creating a reader method."

msgid "## make_writer (;$bool)\n"
"Флаг создания метода-райтера."
msgstr "## make_writer (;$bool)\n"
"Flag for creating a writer method."

i18n/Aion/Types.ru-en.po  view on Meta::CPAN

"* Если `type` строка, то оборачивает его в `Object`.\n"
"* Если `type` можно вызвать, то оборачивает его в `Aion::Type->new(test => $type, ...)`. А если он имеет метод `coerce`, то будет его использовать для преобразоваÐ...
msgstr ""
"* If `type` is `Aion::Type`, then returns it unchanged.\n"
"* If `type` is a string, then wraps it in `Object`.\n"
"* If `type` can be called, then wraps it in `Aion::Type->new(test => $type, ...)`. And if it has a `coerce` method, it will use it for transformations. Thanks to this, it is possible to use external types like `Type::Tiny` in the `Aion` ecosystem."

msgid "Перечисление."
msgstr "Enumeration."

msgid "`undef` или тип в `[]`."
msgstr "`undef` or type in `[]`."

msgid "Только `undef`."
msgstr "Only `undef`."

msgid "Всё за исключением `undef`."
msgstr "Everything except `undef`."

msgid "Определённые значения без ссылок."
msgstr "Defined values without references."

msgid "Определяет значение длины от `from` или 0 до `to`."
msgstr "Specifies a length value from `from` or 0 to `to`."

msgid "Perl версии."
msgstr "Perl version."

i18n/Aion/Types.ru-en.po  view on Meta::CPAN


msgid "И у него перегружены указанные операторы."
msgstr "And the specified operators are overloaded."

msgid "Класс или объект наследует классы из списка."
msgstr "A class or object inherits classes from a list."

msgid "Класс или объект имеет указанные роли."
msgstr "A class or object has the specified roles."

msgid "Проверяет 1, 0, \"\", undef или объект с перегруженным оператором `bool` или `0+` как `JSON::PP::Boolean`. Во втором случае вызывает оператор  `0+` и проверя...
msgstr "Tests for 1, 0, \"\", undef, or an object with an overloaded `bool` or `0+` operator as `JSON::PP::Boolean`. In the second case, it calls the `0+` operator and checks the result as `Bool`."

msgid "`BoolLike` вызывает оператор `0+` и проверяет результат."
msgstr "`BoolLike` calls the `0+` operator and checks the result."

msgid "Строка или объект с перегруженным оператором `\"\"`."
msgstr "A string or object overloaded with the `\"\"` operator."

msgid "Регулярное выражение или объект с перегруженным оператором `qr`."
msgstr "A regular expression or object with an overload of the `qr` operator."

lib/Aion.md  view on Meta::CPAN

	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)

lib/Aion.md  view on Meta::CPAN

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

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

lib/Aion.md  view on Meta::CPAN

	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)

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

lib/Aion.md  view on Meta::CPAN

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` – впустить.

lib/Aion.md  view on Meta::CPAN

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)

lib/Aion.pm  view on Meta::CPAN

#   no - никогда не проверять
use Aion::Env AION_ISA => (default => 'rw');

sub export($@);

# Классы в которых подключён Aion с метаинформацией
our %META;

# Вызывается из другого пакета, для импорта данного
sub import {
	my (undef, $attr) = @_;
	my $pkg = caller;

	*{"$pkg\::DOES"} = \&does if \&does != $pkg->can('DOES');

	if($attr ne '-role') {  # Класс
		export $pkg, qw/extends/;
		*{"${pkg}::new"} = \&initialize;
	} else {	# Роль
		export $pkg, qw/requires req/;
	}

lib/Aion.pm  view on Meta::CPAN

		}
	};

	eval "package $pkg; use Aion::Types; 1" or die;
}

# Удаляет добавленные символы
sub unimport {
	my $pkg = caller;
	
	undef &{"${pkg}::$_"} for qw/extends with aspect requires req/;
	
	eval "package $pkg; no Aion::Types; 1" or die;
}

# Экспортирует функции в пакет, если их там ещё нет
sub export($@) {
	my $pkg = shift;
	for my $sub (@_) {
		my $can = $pkg->can($sub);
		die "$pkg can $sub!" if $can && $can != \&$sub;

lib/Aion.pm  view on Meta::CPAN

		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

=head1 SUBROUTINES IN ROLES

=head2 requires (@subroutine_names)

Checks that classes using this role have the specified routines or features.

lib/Aion.pm  view on Meta::CPAN


The function with C<*> does not hold the meaning:

	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

=head2 isa => $type

Indicates the type, or rather - a validator, feature.

Can take:

=over

=item * C<Aion::Type> – Aion immediately imports all types from L<Aion::Types> into the package.

lib/Aion.pm  view on Meta::CPAN

		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

=head2 coerce => (1|0)

Includes type conversions.

	package ExCoerce { use Aion;

lib/Aion.pm  view on Meta::CPAN

		
	#@eon
	sub power { shift->new }
	
	1;

We use pleroma locally:

	{
		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

See L<Aion::Pleroma>.

=head2 trigger => $sub

C<$sub> is called after setting the property in the constructor (C<new>) or via a setter.

The etymology of C<trigger> is to let in.

	package ExTrigger { use Aion;

lib/Aion.pm  view on Meta::CPAN

	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

=head1 ATTRIBUTES

C<Aion> adds universal attributes to the package.

=head2 :Isa (@signature)

The attribute C<Isa> checks the signature of the function.

lib/Aion/Meta/Feature.md  view on Meta::CPAN


## lazy (;$bool)
Флаг ленивой инициализации.

```perl
$::feature->lazy(1);
$::feature->lazy # -> 1
```

## builder (;$sub)
Билдер значения фичи или `undef`.

```perl
my $builder = sub {};
$::feature->builder($builder);
$::feature->builder # -> $builder
```

## default (;$value)
Значение по умолчанию для фичи.

```perl
$::feature->default(42);
$::feature->default # -> 42
```

## trigger (;$sub)
Обработчик события изменения значения фичи или `undef`.

```perl
my $trigger = sub {};
$::feature->trigger($trigger);
$::feature->trigger # -> $trigger
```

## release (;$sub)
Обработчик события чтения значения из фичи или `undef`.

```perl
my $release = sub {};
$::feature->release($release);
$::feature->release # -> $release
```

## cleaner (;$sub)
Обработчик события удаления фичи из объекта или `undef`.

```perl
my $cleaner = sub {};
$::feature->cleaner($cleaner);
$::feature->cleaner # -> $cleaner
```

## make_reader (;$bool)
Флаг создания метода-ридера.

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


=head2 lazy (;$bool)

Lazy initialization flag.

	$::feature->lazy(1);
	$::feature->lazy # -> 1

=head2 builder (;$sub)

Feature value builder or C<undef>.

	my $builder = sub {};
	$::feature->builder($builder);
	$::feature->builder # -> $builder

=head2 default (;$value)

Default value for the feature.

	$::feature->default(42);
	$::feature->default # -> 42

=head2 trigger (;$sub)

Event handler for feature value change or C<undef>.

	my $trigger = sub {};
	$::feature->trigger($trigger);
	$::feature->trigger # -> $trigger

=head2 release (;$sub)

Event handler for reading a value from a feature or C<undef>.

	my $release = sub {};
	$::feature->release($release);
	$::feature->release # -> $release

=head2 cleaner (;$sub)

Event handler for removing a feature from an object or C<undef>.

	my $cleaner = sub {};
	$::feature->cleaner($cleaner);
	$::feature->cleaner # -> $cleaner

=head2 make_reader (;$bool)

Flag for creating a reader method.

	$::feature->make_reader(1);

lib/Aion/Meta/FeatureConstruct.md  view on Meta::CPAN


```perl
$::construct->add_access('die unless $self->{attr};');
$::construct->{access} # -> 'die unless $self->{attr};'
```

## add_release($code, $unshift)
Добавляет код в геттер после чтения.

```perl
$::construct->add_release('$val = undef;');
$::construct->{release} # -> '$val = undef;'
```

## initializer
Генерирует код для инициализации фичи в конструкторе (`new`).

```perl

$::construct->initializer # -> << 'END'
		if (exists $value{my_feature}) {
			my $val = delete $value{my_feature};

lib/Aion/Meta/FeatureConstruct.md  view on Meta::CPAN

		if (@_>1) {
			my ($self, $val) = @_;
			die if $val < 0;
			$self->{my_feature} = $val;
			$self->on_change;
			$self
		} else {
			my ($self) = @_;
			die unless $self->{attr};
			my $val = $self->{my_feature};
			$val = undef;
			$val
		}
	}
}
END
```

## reader
Генерирует код геттера.

```perl
$::construct->reader # -> <<'END'
package My::Package {
	sub _get_my_feature {
		my ($self) = @_;
		die unless $self->{attr};
		my $val = $self->{my_feature};
		$val = undef;
		$val
	}
}
END
```

## writer
Генерирует код сеттера.

```perl

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


Adds code to the getter before reading the attribute.

	$::construct->add_access('die unless $self->{attr};');
	$::construct->{access} # -> 'die unless $self->{attr};'

=head2 add_release($code, $unshift)

Adds code to the getter after reading.

	$::construct->add_release('$val = undef;');
	$::construct->{release} # -> '$val = undef;'

=head2 initializer

Generates code to initialize a feature in the constructor (C<new>).

	
	$::construct->initializer # -> << 'END'
			if (exists $value{my_feature}) {
				my $val = delete $value{my_feature};
				die if $val < 0;

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

			if (@_>1) {
				my ($self, $val) = @_;
				die if $val < 0;
				$self->{my_feature} = $val;
				$self->on_change;
				$self
			} else {
				my ($self) = @_;
				die unless $self->{attr};
				my $val = $self->{my_feature};
				$val = undef;
				$val
			}
		}
	}
	END

=head2 reader

Generates getter code.

	$::construct->reader # -> <<'END'
	package My::Package {
		sub _get_my_feature {
			my ($self) = @_;
			die unless $self->{attr};
			my $val = $self->{my_feature};
			$val = undef;
			$val
		}
	}
	END

=head2 writer

Generates setter code.

	$::construct->writer # -> <<'END'

lib/Aion/Meta/RequiresAnyFunction.md  view on Meta::CPAN

## new (%args)

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

## compare ($other)

Проверяет, что `$other` является функцией.

```perl
my $any_function = Aion::Meta::RequiresAnyFunction->new(pkg => 'My::Package', name => 'my_function');
eval { $any_function->compare(undef) }; $@  # ~> Requires my_function of My::Package
```

## pkg ()

Возвращает имя пакета, в котором объявлена функция.

```perl
my $any_function = Aion::Meta::RequiresAnyFunction->new(pkg => 'My::Package');
$any_function->pkg  # => My::Package
```

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


=head2 new (%args)

Constructor.

=head2 compare ($other)

Checks that C<$other> is a function.

	my $any_function = Aion::Meta::RequiresAnyFunction->new(pkg => 'My::Package', name => 'my_function');
	eval { $any_function->compare(undef) }; $@  # ~> Requires my_function of My::Package

=head2 pkg ()

Returns the name of the package in which the function is declared.

	my $any_function = Aion::Meta::RequiresAnyFunction->new(pkg => 'My::Package');
	$any_function->pkg  # => My::Package

=head2 name ()

lib/Aion/Meta/Subroutine.md  view on Meta::CPAN

# SYNOPSIS

```perl
use Aion::Types qw(Int);
use Aion::Meta::Subroutine;

my $subroutine = Aion::Meta::Subroutine->new(
	pkg => 'My::Package',
	subname => 'my_subroutine',
	signature => [Int, Int],
	referent => undef,
);

$subroutine->stringify  # => my_subroutine(Int => Int) of My::Package
```

# DESCRIPTION

Служит для объявления требуемой функции в интерфейсах и обстрактных классах.
При этом `referent ~~ Undef`.

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


=head1 SYNOPSIS

	use Aion::Types qw(Int);
	use Aion::Meta::Subroutine;
	
	my $subroutine = Aion::Meta::Subroutine->new(
		pkg => 'My::Package',
		subname => 'my_subroutine',
		signature => [Int, Int],
		referent => undef,
	);
	
	$subroutine->stringify  # => my_subroutine(Int => Int) of My::Package

=head1 DESCRIPTION

Used to declare the required function in interfaces and abstract classes.
In this case, C<referent ~~ Undef>.

It also creates a wrapper function that checks the signature.

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

	MAX_DEPTH => 2,
	MAX_HASH_SIZE => 6,
	MAX_ARRAY_SIZE => 6,
	MAX_SCALAR_LENGTH => 255,
};

sub val_to_str($;$);
sub val_to_str($;$) {
	my ($v, $depth) = @_;
	
	if (!defined $v) { 'undef' }
	elsif (ref $v eq 'ARRAY') {
		if($depth > MAX_DEPTH) { '[...]' }
		else {
			$depth++;
			join '', '[', join(', ', map({ val_to_str($_, $depth) } (
				@$v > MAX_ARRAY_SIZE ? @$v[0..MAX_ARRAY_SIZE] : @$v
			)), @$v > MAX_ARRAY_SIZE ? '...' : ()), ']';
		}
	}
	elsif (ref $v eq 'HASH') {

lib/Aion/Pleroma.md  view on Meta::CPAN


Aion::Pleroma - контейнер эонов

# SYNOPSIS

```perl
use Aion::Pleroma;

my $pleroma = Aion::Pleroma->new;

$pleroma->get('user') # -> undef
$pleroma->resolve('user') # @-> user is'nt eon!
```

# DESCRIPTION

Реализует паттерн контейнера зависимостей.

Эон создаётся при запросе из контейнера через метод `get` или `resolve`, либо через аспект `eon` как ленивый `default`. Ленивость можно отменить через ...

Контейнер можно получить с помощью `Aion->pleroma`.

lib/Aion/Pleroma.md  view on Meta::CPAN

```

# SUBROUTINES

## get ($key)

Получить эон из контейнера.

```perl
my $pleroma = Aion::Pleroma->new;
$pleroma->get('') # -> undef
$pleroma->get('Ex::Eon::AnimalEon#dog')->role # => dog
```

## resolve ($key)

Получить эон из контейнера или исключение, если его там нет.

```perl
my $pleroma = Aion::Pleroma->new;
$pleroma->resolve('e.ibex') # @=> e.ibex is'nt eon!

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

	return $eon if $eon;
	
	my $config = $self->pleroma->{$key};
	if(ref $config eq 'HASH') {
		$self->{eon}{$key} = $self->build($key, $config);
	}
	elsif($config) {
		$self->{eon}{$key} = $self->construct($config, []);
	}
	elsif(AION_PLEROMA_AUTOWARE and $key =~ /^([\w:]+)(#\w+)?$/ and eval "require $1") { $self->autoware($key)->get($key) }
	else { undef }
}

# Построить эон из хеш-описания: class, method, arguments, calls
sub build {
	my ($self, $key, $conf) = @_;

	my $pkg = $conf->{class} // ($key =~ /^[\w:]+$/ ? $key : undef)
		or die "Eon $key: class is undef! Optional 'class' key or key-as-class.";
	my $method = $conf->{method} // 'new';

	$self->_require($pkg);

	my $args = $conf->{arguments} // {};
	$args = $self->resolve_args($args);

	my $eon = $self->construct("$pkg#$method", $args);

	for my $call (@{ $conf->{calls} // [] }) {

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

=head1 NAME

Aion::Pleroma - container of aeons

=head1 SYNOPSIS

	use Aion::Pleroma;
	
	my $pleroma = Aion::Pleroma->new;
	
	$pleroma->get('user') # -> undef
	$pleroma->resolve('user') # @-> user is'nt eon!

=head1 DESCRIPTION

Implements the dependency container pattern.

An eon is created when requesting from a container via the C<get> or C<resolve> method, or via the C<eon> aspect as a lazy C<default>. Laziness can be canceled via the C<lazy> aspect.

The container can be obtained using C<< Aion-E<gt>pleroma >>.

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

	my $cat = $pleroma->resolve('ex.cat');
	$pleroma->eon # --> { "ex.cat" => $cat, "Aion::Pleroma" => $pleroma }

=head1 SUBROUTINES

=head2 get ($key)

Receive an eon from the container.

	my $pleroma = Aion::Pleroma->new;
	$pleroma->get('') # -> undef
	$pleroma->get('Ex::Eon::AnimalEon#dog')->role # => dog

=head2 resolve ($key)

Get an eon from the container or an exception if it is not there.

	my $pleroma = Aion::Pleroma->new;
	$pleroma->resolve('e.ibex') # @=> e.ibex is'nt eon!
	$pleroma->resolve('Ex::Eon::AnimalEon#dog')->role # => dog

lib/Aion/Type.md  view on Meta::CPAN


```perl
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) }];

$Int->coerce(5.5)	 # => 6
$Int->coerce(undef)  # => 0
$Int->coerce("abc")  # => abc
```

## detail ($element, $feature)

Формирует сообщение ошибки.

```perl
my $Int = Aion::Type->new(name => "Int");

lib/Aion/Type.md  view on Meta::CPAN

```perl
Aion::Types::Int->is_range_type  # -> ""
Aion::Types::Len([10])->is_range_type  # -> 1
```

## range_lbound ()

Нижняя граница интервала.

```perl
Aion::Types::Int->range_lbound  # -> undef
Aion::Types::Len([10])->range_lbound  # -> 0
Aion::Types::Range([0, 10])->range_lbound  # -> '-Inf'
```

## is_range ()

Это интервал.

```perl
Aion::Types::Int->is_range  # -> ""

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

# Формирует ключ с отсортированными нетипизированными параметрами
sub sorted_args_key {
	my ($self) = @_;
	my $coerceaddr = Scalar::Util::refaddr $self->{coerce};
	join "-", $coerceaddr, join(",", map { join ":", length($_), $_ } sort @{$self->{args}});
}

# Возвращает уникальный ключ для типа, использующийся в хешах и сравнения
# Должен быть заменён на созданные типы
my %keyfn;
my $undefined = [];
sub key {
	my ($self) = @_;
	$self->{key} //= do {
		my $coerceaddr = Scalar::Util::refaddr $self->{coerce};
		my $keyfn = $keyfn{$coerceaddr};
		$keyfn
			? $keyfn->($self)
			: join "-", $coerceaddr, exists $self->{args} && @{$self->{args}} || exists $self->{N} || exists $self->{M}
				? join(",", map {
					my $key = UNIVERSAL::isa($_, __PACKAGE__)? $_->key: "" . ($_ // $undefined);
					join ":", length($key), $key 
				} @{$self->{args}})
				: ();
	};
}

# Устанавливает/возвращает функцию построения ключа для типа как класса
sub keyfn {
	my ($self, $fn) = @_;
	if(@_>1) {

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

Corresponds to the C<< E<gt>E<gt> >> operator.

	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) }];
	
	$Int->coerce(5.5)	 # => 6
	$Int->coerce(undef)  # => 0
	$Int->coerce("abc")  # => abc

=head2 detail ($element, $feature)

Generates an error message.

	my $Int = Aion::Type->new(name => "Int");
	
	$Int->detail(-5, "Feature car") # => Feature car must have the type Int. The it is -5!
	

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


This is an interval type.

	Aion::Types::Int->is_range_type  # -> ""
	Aion::Types::Len([10])->is_range_type  # -> 1

=head2 range_lbound ()

Lower limit of the interval.

	Aion::Types::Int->range_lbound  # -> undef
	Aion::Types::Len([10])->range_lbound  # -> 0
	Aion::Types::Range([0, 10])->range_lbound  # -> '-Inf'

=head2 is_range ()

This is an interval.

	Aion::Types::Int->is_range  # -> ""
	Aion::Types::Len([10])->is_range  # -> ""
	Aion::Types::Range([1, 10])->is_range  # -> 1

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

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!
```

Стандартные приведения:

```perl
# 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)  # -> ""
```

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


my $myint = bless {}, 'MyInt';

External([$myint]) ~~ '+123' # -> 1
External([$myint])->coerce(10.1) # => 10
External([$myint])->coerce('abc') # => abc
```

## Bool

`1` is true. `0`, `""` or `undef` is false.

```perl
1 ~~ Bool  # -> 1
0 ~~ Bool  # -> 1
undef ~~ Bool # -> 1
"" ~~ Bool # -> 1

2 ~~ Bool  # -> ""
[] ~~ Bool # -> ""
```

## Enum[A...]

Перечисление.

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

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

## Maybe[A]

`undef` или тип в `[]`.

```perl
undef ~~ Maybe[Int] # -> 1
4 ~~ Maybe[Int]     # -> 1
"" ~~ Maybe[Int]    # -> ""
```

## Undef

Только `undef`.

```perl
undef ~~ Undef # -> 1
0 ~~ Undef     # -> ""
```

## Defined

Всё за исключением `undef`.

```perl
\0 ~~ Defined    # -> 1
undef ~~ Defined # -> ""
```

## Value

Определённые значения без ссылок.

```perl
3 ~~ Value  # -> 1
\3 ~~ Value    # -> ""
undef ~~ Value # -> ""
```

## Len[from?, to]

Определяет значение длины от `from` или 0 до `to`.

```perl
"1234" ~~ Len[3]   # -> ""
"123" ~~ Len[3]    # -> 1
"12" ~~ Len[3]     # -> 1

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

## ArrayRef`[A]

Ссылки на массивы.

```perl
[] ~~ ArrayRef	# -> 1
{} ~~ ArrayRef	# -> ""
[] ~~ ArrayRef[Num]	# -> 1
{} ~~ ArrayRef[Num]	# -> ''
[1, 1.1] ~~ ArrayRef[Num]	# -> 1
[1, undef] ~~ ArrayRef[Num]	# -> ""
```

## Lim[from?, to]

Ограничивает массивы от `from` или 0 до `to` элементов.

```perl
[] ~~ Lim[5]     # -> 1
[1..5] ~~ Lim[5] # -> 1
[1..6] ~~ Lim[5] # -> ""

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


'RoleExample' ~~ ConsumerOf[qw/Role1/] # -> 1
'RoleExample' ~~ ConsumerOf[qw/Role2 Role1/] # -> 1
bless({}, 'RoleExample') ~~ ConsumerOf[qw/Role3 Role2 Role1/] # -> ""

'NoneExample' ~~ ConsumerOf[qw/Role1/] # -> ""
```

## BoolLike

Проверяет 1, 0, "", undef или объект с перегруженным оператором `bool` или `0+` как `JSON::PP::Boolean`. Во втором случае вызывает оператор  `0+` и проверяет ре...

`BoolLike` вызывает оператор `0+` и проверяет результат.

```perl
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
```

## StrLike

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

[] ~~ 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
```

## HashLike`[A]

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


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;

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

	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)

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

	}
	
	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

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

	
	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

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


=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

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

	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

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

	[] ~~ 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]

t/aion.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 - постмодернистская объектная система для Perl 5, такая как «Mouse», «Moose», «Moo», «Mo» и «M», но с улучшениями
# 
# # VERSION
# 
# 2.2
# 
# # SYNOPSIS
# 

t/aion.t  view on Meta::CPAN

	has b => (is => 'ro+', isa => Num);
	has op => (is => 'ro', isa => Enum[qw/+ - * \/ **/], default => '+');

	sub result : Isa(Me => Num) {
		my ($self) = @_;
		eval "${\ $self->a} ${\ $self->op} ${\ $self->b}";
	}

}

local ($::_g0 = do {Calc->new(a => 1.1, b => 2)->result}, $::_e0 = "3.1"); ::ok $::_g0 eq $::_e0, 'Calc->new(a => 1.1, b => 2)->result   # => 3.1' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# # DESCRIPTION
# 
# Aion — ООП-фреймворк для создания классов с **фичами**, имеет **аспекты**, **роли** и так далее.
# 
# Свойства, объявленные через has, называются **фичами**.
# 
# А `is`, `isa`, `default` и так далее в `has` называются **аспектами**.
# 

t/aion.t  view on Meta::CPAN

#>> 
#>> 1;
#@< EOF
# 
::done_testing; }; subtest 'has ($name, %aspects)' => sub { 
use lib "lib";
use Animal;

my $cat = Animal->new(type => 'cat');

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

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

# 
# ## with
# 
# Добавляет в модуль роли. Для каждой роли вызывается метод `import_with`.
# 
# Файл lib/Role/Keys/Stringify.pm:
#@> lib/Role/Keys/Stringify.pm
#>> package Role::Keys::Stringify;
#>> 

t/aion.t  view on Meta::CPAN

#>> 
#>> 1;
#@< EOF
# 
::done_testing; }; subtest 'with' => sub { 
use lib "lib";
use Class::All::Stringify;

my $s = Class::All::Stringify->new(key1=>"a", key2=>"b");

local ($::_g0 = do {$s->keysify}, $::_e0 = "key1, key2"); ::ok $::_g0 eq $::_e0, '$s->keysify	 # => key1, key2' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$s->valsify}, $::_e0 = "a, b"); ::ok $::_g0 eq $::_e0, '$s->valsify	 # => a, b' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## exactly ($package)
# 
# Проверяет, что `$package` — это суперкласс для данного или сам этот класс.
# 
# Реализацию метода `isa` Aion не меняет и она находит как суперклассы, так и роли (так как и те и другие добавляются в `@ISA` пакета).
# 
::done_testing; }; subtest 'exactly ($package)' => sub { 
package Ex::X { use Aion; }
package Ex::A { use Aion; extends q/Ex::X/; }
package Ex::B { use Aion; }
package Ex::C { use Aion; extends qw/Ex::A Ex::B/ }

local ($::_g0 = do {Ex::C->exactly("Ex::A")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::C->exactly("Ex::A") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::C->exactly("Ex::B")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::C->exactly("Ex::B") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::C->exactly("Ex::X")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::C->exactly("Ex::X") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::C->exactly("Ex::X1")}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::C->exactly("Ex::X1") # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::A->exactly("Ex::X")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::A->exactly("Ex::X") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::A->exactly("Ex::A")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::A->exactly("Ex::A") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::X->exactly("Ex::X")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::X->exactly("Ex::X") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## does ($package)
# 
# Проверяет, что `$package` — это роль, которая используется в классе или другой роли.
# 
::done_testing; }; subtest 'does ($package)' => sub { 
package Role::X { use Aion -role; }
package Role::A { use Aion -role; with qw/Role::X/; }
package Role::B { use Aion -role; }
package Ex::Z { use Aion; with qw/Role::A Role::B/; }

local ($::_g0 = do {Ex::Z->does("Role::A")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::Z->does("Role::A") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::Z->does("Role::B")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::Z->does("Role::B") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::Z->does("Role::X")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::Z->does("Role::X") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Role::A->does("Role::X")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Role::A->does("Role::X") # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Role::A->does("Role::X1")}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Role::A->does("Role::X1") # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Ex::Z->does("Ex::Z")}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Ex::Z->does("Ex::Z") # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## aspect ($aspect => sub { ... })
# 
# Добавляет аспект к `has` в текущем классе и его классам-наследникам или текущей роли и применяющим её классам.
# 
::done_testing; }; subtest 'aspect ($aspect => sub { ... })' => sub { 
package Example::Earth {
	use Aion;

t/aion.t  view on Meta::CPAN

		$feature->construct->add_attr(":lvalue");
	};

	has moon => (is => "rw", lvalue => 1);
}

my $earth = Example::Earth->new;

$earth->moon = "Mars";

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

# 
# Аспект вызывается каждый раз, когда он указан в `has`.
# 
# Создатель аспекта имеет параметры:
# 
# * `$value` — значение аспекта.
# * `$feature` — метаобъект описывающий фичу (`Aion::Meta::Feature`).
# * `$aspect_name` — наименование аспекта.
# 

package Example::Mars {
	use Aion;

	aspect lvalue => sub {
		my ($value, $feature, $aspect_name) = @_;

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

		$feature->construct->add_attr(":lvalue");
	};

	has moon => (is => "rw", lvalue => 1);
}

# 
# ## pleroma ()
# 
# Возвращает локатор.
# 
::done_testing; }; subtest 'pleroma ()' => sub { 
local ($::_g0 = do {Aion->pleroma->isa('Aion::Pleroma')}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Aion->pleroma->isa(\'Aion::Pleroma\')  # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::...

# 
# # SUBROUTINES IN CLASSES
# 
# ## extends (@superclasses)
# 
# Расширяет класс другим классом/классами. Он вызывает из каждого наследуемого класса метод `import_extends`, если он в нём есть.
# 
::done_testing; }; subtest 'extends (@superclasses)' => sub { 
package World { use Aion;

	our $extended_by_this = 0;

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

local ($::_g0 = do {$class}, $::_e0 = "World"); ::ok $::_g0 eq $::_e0, '		$class   # => World' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$extends}, $::_e0 = "Hello"); ::ok $::_g0 eq $::_e0, '		$extends # => Hello' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
	}
}

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

local ($::_g0 = do {$World::extended_by_this}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	$World::extended_by_this # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

local ($::_g0 = do {Hello->isa("World")}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Hello->isa("World")	 # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## new (%param)
# 
# Конструктор.
# 
# * Устанавливает `%param` для фич.
# * Проверяет, что параметры соответствуют фичам.
# * Устанавливает значения по умолчанию.
# 
::done_testing; }; subtest 'new (%param)' => sub { 
package NewExample { use Aion;
	has x => (is => 'ro', isa => Num);
	has y => (is => 'ro+', isa => Num);
	has z => (is => 'ro-', isa => Num);
}

eval {NewExample->new(f => 5)}; local ($::_g0 = $@, $::_e0 = 'y required!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'NewExample->new(f => 5) # @-> y required!' or ::diag ::_string_diff($::_g0, $::_e0, 1); undef $::_g0; undef $::_e0;
eval {NewExample->new(f => 5, y => 10)}; local ($::_g0 = $@, $::_e0 = 'f is\'nt feature!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'NewExample->new(f => 5, y => 10) # @-> f is\'nt feature!' or ::diag ::_string_diff($::_g0, $::_e0, 1...
eval {NewExample->new(f => 5, p => 6, y => 10)}; local ($::_g0 = $@, $::_e0 = 'f, p is\'nt features!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'NewExample->new(f => 5, p => 6, y => 10) # @-> f, p is\'nt features!' or ::diag ::_strin...
eval {NewExample->new(z => 10, y => 10)}; local ($::_g0 = $@, $::_e0 = 'z excessive!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'NewExample->new(z => 10, y => 10) # @-> z excessive!' or ::diag ::_string_diff($::_g0, $::_e0, 1); undef...

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

eval {$ex->x}; local ($::_g0 = $@, $::_e0 = 'Get feature x must have the type Num. The it is undef!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, '$ex->x # @-> Get feature x must have the type Num. The it is undef!' or ::diag ::_string_...

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

local ($::_g0 = do {$ex->x}, $::_e0 = do {10.1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->x # -> 10.1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# # SUBROUTINES IN ROLES
# 
# ## requires (@subroutine_names)
# 
# Проверяет, что в классах, использующих эту роль, есть указанные подпрограммы или фичи.
# 
::done_testing; }; subtest 'requires (@subroutine_names)' => sub { 
package Role::Alpha { use Aion -role;

	requires qw/abc/;
}

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

::like scalar do {eval { Omega1->new }; $@}, qr{Requires abc of Role::Alpha}, 'eval { Omega1->new }; $@ # ~> Requires abc of Role::Alpha'; undef $::_g0; undef $::_e0;

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

	sub abc { "abc" }
}

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

# 
# ## req ($name => @aspects)
# 
# Проверяет, что в классах, использующих эту роль, есть указанные фичи с указанными аспектами.
# 
::done_testing; }; subtest 'req ($name => @aspects)' => sub { 
package Role::Beta { use Aion -role;

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

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

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

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

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

local ($::_g0 = do {Omega3->new->x}, $::_e0 = do {12}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Omega3->new->x  # -> 12' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## Роль наследует роль
# 
# Роль может наследовать другую роль через `with`. Так можно уточнять интерфейс: типы требующихся фичей (`req`) и методов (`:Isa`) либо остаются таÐ...
# 
# Роль `Role::Animal` требует свойство `legs` широкого типа `Num | Object` и метод `sound` с сигнатурой `(Me => Str)`.
# 
::done_testing; }; subtest 'Роль наследует роль' => sub { 
package Role::Animal { use Aion -role;

t/aion.t  view on Meta::CPAN

# 
# Класс `Ex::Sparrow` использует роль `Role::Bird` и реализует все её требования.
# 

package Ex::Sparrow { use Aion;
	with qw/Role::Bird/;

	has legs => (is => 'ro', isa => Num, default => 2);
	sub sound : Isa(Me => Str) { 'chirp' }

local ($::_g0 = do {Num < (Num | Object)}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	Num < (Num | Object)  # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

my $sparrow = Ex::Sparrow->new;
local ($::_g0 = do {$sparrow->legs}, $::_e0 = "2"); ::ok $::_g0 eq $::_e0, '$sparrow->legs  # => 2' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$sparrow->sound}, $::_e0 = "chirp"); ::ok $::_g0 eq $::_e0, '$sparrow->sound # => chirp' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# # ASPECTS
# 
# `use Aion` включает в модуль следующие аспекты для использования в `has`:
# 
# ## is => $permissions
# 
# * `ro` — создать только геттер.
# * `wo` — создать только сеттер.

t/aion.t  view on Meta::CPAN

# * `?` – создать предикат.
# * `!` – создать clearer.
# 
::done_testing; }; subtest 'is => $permissions' => sub { 
package ExIs { use Aion;
	has rw => (is => 'rw?!');
	has ro => (is => 'ro+');
	has wo => (is => 'wo-?');
}

eval {ExIs->new}; local ($::_g0 = $@, $::_e0 = 'ro required!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'ExIs->new # @-> ro required!' or ::diag ::_string_diff($::_g0, $::_e0, 1); undef $::_g0; undef $::_e0;
eval {ExIs->new(ro => 10, wo => -10)}; local ($::_g0 = $@, $::_e0 = 'wo excessive!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'ExIs->new(ro => 10, wo => -10) # @-> wo excessive!' or ::diag ::_string_diff($::_g0, $::_e0, 1); undef $::...

local ($::_g0 = do {ExIs->new(ro => 10)->has_rw}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIs->new(ro => 10)->has_rw # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {ExIs->new(ro => 10, rw => 20)->has_rw}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIs->new(ro => 10, rw => 20)->has_rw # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $:...
local ($::_g0 = do {ExIs->new(ro => 10, rw => 20)->clear_rw->has_rw}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIs->new(ro => 10, rw => 20)->clear_rw->has_rw # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); ...

local ($::_g0 = do {ExIs->new(ro => 10)->ro}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIs->new(ro => 10)->ro  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

local ($::_g0 = do {ExIs->new(ro => 10)->wo(30)->has_wo}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIs->new(ro => 10)->wo(30)->has_wo # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0...
eval {ExIs->new(ro => 10)->wo}; local ($::_g0 = $@, $::_e0 = 'Feature wo cannot be get!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'ExIs->new(ro => 10)->wo # @-> Feature wo cannot be get!' or ::diag ::_string_diff($::_g0, $::_e0, 1);...
local ($::_g0 = do {ExIs->new(ro => 10)->rw(30)->rw}, $::_e0 = do {30}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIs->new(ro => 10)->rw(30)->rw  # -> 30' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

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

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

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

local ($::_g0 = do {$node->parent->parent}, $::_e0 = do {undef}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$node->parent->parent   # -> undef' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
undef $root;
local ($::_g0 = do {$node->parent}, $::_e0 = do {undef}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$node->parent   # -> undef' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

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

local ($::_g0 = do {$node->parent->parent}, $::_e0 = do {undef}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$node->parent->parent   # -> undef' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
undef $root;
local ($::_g0 = do {$node->parent}, $::_e0 = do {undef}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$node->parent   # -> undef' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## isa => $type
# 
# Указывает тип, а точнее – валидатор, фичи.
# 
# Может принимать:
# 
# * `Aion::Type` – Aion сразу импортирует в пакет все типы из [Aion::Types](https://metacpan.org/pod/Aion::Types).
# * Строки воспримаются как пакеты и оборачиваются в `Object`.

t/aion.t  view on Meta::CPAN

	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);
}

eval {ExIsa->new(x => 'str')}; local ($::_g0 = $@, $::_e0 = 'Set feature x must have the type Int. The it is \'str\'!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'ExIsa->new(x => \'str\') # @-> Set feature x must have the type Int. Th...
eval {ExIsa->new->x}; local ($::_g0 = $@, $::_e0 = 'Get feature x must have the type Int. The it is undef!'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'ExIsa->new->x # @-> Get feature x must have the type Int. The it is undef!' or ::d...
local ($::_g0 = do {ExIsa->new(x => 10)->x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIsa->new(x => 10)->x			  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

eval {ExIsa->new(y => 'abc')}; local ($::_g0 = $@, $::_e0 = 'Set feature y must have the type External[CODE'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'ExIsa->new(y => \'abc\') # @-> Set feature y must have the type External[CODE' or...
local ($::_g0 = do {ExIsa->new(z => ' 6 xyz')->z}, $::_e0 = do {6}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExIsa->new(z => \' 6 xyz\')->z # -> 6' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## coerce => (1|0)
# 
# Включает преобразования типов.
# 
::done_testing; }; subtest 'coerce => (1|0)' => sub { 
package ExCoerce { use Aion;
	has x => (is => 'ro', isa => Int, coerce => 1);
}

local ($::_g0 = do {ExCoerce->new(x => 10.4)->x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExCoerce->new(x => 10.4)->x  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {ExCoerce->new(x => 10.5)->x}, $::_e0 = do {11}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExCoerce->new(x => 10.5)->x  # -> 11' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## default => $value
# 
# Значение по умолчанию устанавливается в конструкторе, если параметр с именем фичи отсутствует.
# 
::done_testing; }; subtest 'default => $value' => sub { 
package ExDefault { use Aion;
	has x => (is => 'ro', default => 10);
}

local ($::_g0 = do {ExDefault->new->x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExDefault->new->x  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {ExDefault->new(x => 20)->x}, $::_e0 = do {20}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'ExDefault->new(x => 20)->x  # -> 20' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

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

my $count = 10;

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

my $ex = ExLazy->new;
local ($::_g0 = do {$count}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$count   # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$ex->x}, $::_e0 = do {11}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->x   # -> 11' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$count}, $::_e0 = do {11}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$count   # -> 11' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$ex->x}, $::_e0 = do {11}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->x   # -> 11' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$count}, $::_e0 = do {11}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$count   # -> 11' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## lazy => (1|0)
# 
# Аспект `lazy` включает или отключает ленивое вычисление значения по умолчанию (`default`).
# 
# По умолчанию он включен только если значение по умолчанию является подпрограммой.
# 
::done_testing; }; subtest 'lazy => (1|0)' => sub { 
package ExLazy0 { use Aion;
	has x => (is => 'ro?', lazy => 0, default => sub { 5 });
}

my $ex0 = ExLazy0->new;
local ($::_g0 = do {$ex0->has_x}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex0->has_x # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$ex0->x}, $::_e0 = do {5}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex0->x     # -> 5' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

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

my $ex1 = ExLazy1->new;
local ($::_g0 = do {$ex1->has_x}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex1->has_x # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$ex1->x}, $::_e0 = do {6}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex1->x     # -> 6' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## eon => (1|2|$key)
# 
# С помощью аспекта `eon` реализуется паттерн **Dependency Injection**.
# 
# Он связывает свойство с сервисом из контейнера `Aion->pleroma`.
# 
# Значением аспекта может быть ключ сервиса, 1 или 2.
# 

t/aion.t  view on Meta::CPAN

#>> sub power { shift->new }
#>> 
#>> 1;
#@< EOF
# 
# Используем плерому локально:
# 
::done_testing; }; subtest 'eon => (1|2|$key)' => sub { 
{
	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');

local ($::_g0 = do {$counter->accomulator->power->counter}, $::_e0 = do {$counter}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	$counter->accomulator->power->counter # -> $counter' or ::diag ::_struct_diff($::_g0, $::_e0); undef $...
}

local ($::_g0 = do {Aion->pleroma->get('ex.counter')}, $::_e0 = do {undef}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Aion->pleroma->get(\'ex.counter\') # -> undef' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $:...

# 
# См. [Aion::Pleroma](https://metacpan.org/pod/Aion::Pleroma).
# 
# ## trigger => $sub
# 
# `$sub` вызывается после установки свойства в конструкторе (`new`) или через сеттер.
# 
# Этимология `trigger` – впустить.
# 

t/aion.t  view on Meta::CPAN

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);
local ($::_g0 = do {$ex->y}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->y	  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
$ex->x(20);
local ($::_g0 = do {$ex->y}, $::_e0 = do {30}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->y	  # -> 30' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## release => $sub
# 
# `$sub` вызывается перед возвратом свойства из объекта через геттер.
# 
# Этимология `release` – выпустить.
# 
::done_testing; }; subtest 'release => $sub' => sub { 
package ExRelease { use Aion;
	has x => (release => sub {
		my ($self, $value) = @_;
		$_[1] = $value + 1;
	});
}

my $ex = ExRelease->new(x => 10);
local ($::_g0 = do {$ex->x}, $::_e0 = do {11}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->x	  # -> 11' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## init_arg => $name
# 
# Меняет имя свойства в конструкторе.
# 
::done_testing; }; subtest 'init_arg => $name' => sub { 
package ExInitArg { use Aion;
	has x => (is => 'ro+', init_arg => 'init_x');

local ($::_g0 = do {ExInitArg->new(init_x => 10)->x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	ExInitArg->new(init_x => 10)->x # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

# 
# ## accessor => $name
# 
# Меняет имя акцессора.
# 
::done_testing; }; subtest 'accessor => $name' => sub { 
package ExAccessor { use Aion;
	has x => (is => 'rw', accessor => '_x');

local ($::_g0 = do {ExAccessor->new->_x(10)->_x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	ExAccessor->new->_x(10)->_x # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

# 
# ## writer => $name
# 
# Создаёт сеттер с именем `$name` для свойства.
# 
::done_testing; }; subtest 'writer => $name' => sub { 
package ExWriter { use Aion;
	has x => (is => 'ro', writer => '_set_x');

local ($::_g0 = do {ExWriter->new->_set_x(10)->x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	ExWriter->new->_set_x(10)->x # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

# 
# ## reader => $name
# 
# Создаёт геттер с именем `$name` для свойства.
# 
::done_testing; }; subtest 'reader => $name' => sub { 
package ExReader { use Aion;
	has x => (is => 'wo', reader => '_get_x');

local ($::_g0 = do {ExReader->new(x => 10)->_get_x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	ExReader->new(x => 10)->_get_x # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

# 
# ## predicate => $name
# 
# Создаёт предикат с именем `$name` для свойства. Создать предикат со стандартным именем можно так же через  `is => '?'`.
# 
::done_testing; }; subtest 'predicate => $name' => sub { 
package ExPredicate { use Aion;
	has x => (predicate => '_has_x');
	
	my $ex = ExPredicate->new;
local ($::_g0 = do {$ex->_has_x}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	$ex->_has_x        # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$ex->x(10)->_has_x}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '	$ex->x(10)->_has_x # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
}

# 
# ## clearer => $name
# 
# Создаёт очиститель с именем `$name` для свойства. Создать очиститель со стандартным именем можно так же через  `is => '!'`.
# 
::done_testing; }; subtest 'clearer => $name' => sub { 
package ExClearer { use Aion;
	has x => (is => '?', clearer => 'clear_x_');
}

my $ex = ExClearer->new;
local ($::_g0 = do {$ex->has_x}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->has_x	  # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
$ex->clear_x_;
local ($::_g0 = do {$ex->has_x}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->has_x	  # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
$ex->x(10);
local ($::_g0 = do {$ex->has_x}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->has_x	  # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
$ex->clear_x_;
local ($::_g0 = do {$ex->has_x}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ex->has_x	  # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## cleaner => $sub
# 
# `$sub` вызывается при вызове декструктора или `$object->clear_feature`, но только если свойство имеется (см. `$object->has_feature`).
# 
# Данный аспект принудительно создаёт предикат и clearer.
# 
::done_testing; }; subtest 'cleaner => $sub' => sub { 
package ExCleaner { use Aion;

	our $x;

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

local ($::_g0 = do {$ExCleaner::x}, $::_e0 = do {undef}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ExCleaner::x		  # -> undef' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
ExCleaner->new(x => 10);
local ($::_g0 = do {$ExCleaner::x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ExCleaner::x		  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

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

local ($::_g0 = do {$ExCleaner::x}, $::_e0 = do {10}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ExCleaner::x	  # -> 10' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
$ex->clear_x;
local ($::_g0 = do {$ExCleaner::x}, $::_e0 = do {12}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ExCleaner::x	  # -> 12' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

undef $ex;

local ($::_g0 = do {$ExCleaner::x}, $::_e0 = do {12}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$ExCleaner::x	  # -> 12' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# # ATTRIBUTES
# 
# `Aion` добавляет в пакет универсальные атрибуты.
# 
# ## :Isa (@signature)
# 
# Атрибут `Isa` проверяет сигнатуру функции.
# 
::done_testing; }; subtest ':Isa (@signature)' => sub { 
package MaybeCat { use Aion;

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

my $anim = MaybeCat->new;
local ($::_g0 = do {$anim->is_cat('cat')}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$anim->is_cat(\'cat\')	# -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$anim->is_cat('dog')}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$anim->is_cat(\'dog\')	# -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

eval {MaybeCat->is_cat("cat")}; local ($::_g0 = $@, $::_e0 = 'Arguments of method `is_cat` must have the type Tuple[Me, Str].'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'MaybeCat->is_cat("cat") # @-> Arguments of method `is_cat` must...
eval {my @items = $anim->is_cat("cat")}; local ($::_g0 = $@, $::_e0 = 'Returns of method `is_cat` must have the type Tuple[Bool].'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'my @items = $anim->is_cat("cat") # @-> Returns of method `i...

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

package Anim { use Aion -role;

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

t/aion.t  view on Meta::CPAN

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

local ($::_g0 = do {Cat->new->is_cat}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Cat->new->is_cat # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Dog->new->is_cat}, $::_e0 = do {0}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'Dog->new->is_cat # -> 0' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
eval {Mouse->new}; local ($::_g0 = $@, $::_e0 = 'Signature mismatch: is_cat(Me => Bool) of Anim <=> is_cat(Me => Int) of Mouse'); ok defined($::_g0) && $::_g0 =~ /^${\quotemeta $::_e0}/, 'Mouse->new # @-> Signature mismatch: is_cat(Me => Bool) of Ani...

# 
# # SEE ALSO
# 
# Экосистема Aion:
# 
# * [Aion::Annotation](https://metacpan.org/pod/Aion::Annotation)
# * [Aion::Carp](https://metacpan.org/pod/Aion::Carp)
# * [Aion::Enum](https://metacpan.org/pod/Aion::Enum)
# * [Aion::Format](https://metacpan.org/pod/Aion::Format)

t/aion/meta/feature-construct.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::Meta::FeatureConstruct - конструктор акцессора, предиката, инициализатора и очистителя
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
use Aion::Meta::FeatureConstruct;

our $construct = Aion::Meta::FeatureConstruct->new('My::Package', 'my_feature');

$construct->add_attr(':lvalue');

local ($::_g0 = do {$construct->accessor}, $::_e0 = do {<< 'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$construct->accessor # -> << \'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
package My::Package {
	sub my_feature:lvalue {
		if (@_>1) {
			my ($self, $val) = @_;
			$self->{my_feature} = $val;
			$self
		} else {
			my ($self) = @_;
			$self->{my_feature}
		}

t/aion/meta/feature-construct.t  view on Meta::CPAN

# 
# ## new ($pkg, $name)
# 
# Конструктор.
# 
# ## pkg
# 
# Пакет, к которому относится атрибут. Геттер.
# 
::done_testing; }; subtest 'pkg' => sub { 
local ($::_g0 = do {$::construct->pkg}, $::_e0 = do {"My::Package"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->pkg # -> "My::Package"' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# ## name
# 
# Имя атрибута. Геттер. 
# 
::done_testing; }; subtest 'name' => sub { 
local ($::_g0 = do {$::construct->name}, $::_e0 = do {"my_feature"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->name # -> "my_feature"' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## write
# 
# Код для записи значения. Геттер.
# 
::done_testing; }; subtest 'write' => sub { 
local ($::_g0 = do {$::construct->write}, $::_e0 = '%(preset)s%(set)s%(trigger)s'); ::ok $::_g0 eq $::_e0, '$::construct->write # \> %(preset)s%(set)s%(trigger)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## read
# Код для чтения значения. Геттер.
# 
::done_testing; }; subtest 'read' => sub { 
local ($::_g0 = do {$::construct->read}, $::_e0 = '%(access)s%(getvar)s%(release)s%(ret)s'); ::ok $::_g0 eq $::_e0, '$::construct->read # \> %(access)s%(getvar)s%(release)s%(ret)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## getvar
# Переменная для получения значения. Геттер.
# 
::done_testing; }; subtest 'getvar' => sub { 
local ($::_g0 = do {$::construct->getvar}, $::_e0 = '%(get)s'); ::ok $::_g0 eq $::_e0, '$::construct->getvar # \> %(get)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## ret
# Код возврата значения. Геттер.
# 
::done_testing; }; subtest 'ret' => sub { 
local ($::_g0 = do {$::construct->ret}, $::_e0 = do {''}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->ret # -> \'\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## init_arg
# Ключ в хеше инициализации. Акцессор.
# 
::done_testing; }; subtest 'init_arg' => sub { 
local ($::_g0 = do {$::construct->init_arg}, $::_e0 = '%(name)s'); ::ok $::_g0 eq $::_e0, '$::construct->init_arg # \> %(name)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## set
# Код установки значения в хеш объекта. Акцессор.
# 
::done_testing; }; subtest 'set' => sub { 
local ($::_g0 = do {$::construct->set}, $::_e0 = '$self->{%(name)s} = $val;'); ::ok $::_g0 eq $::_e0, '$::construct->set # \> $self->{%(name)s} = $val;' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## get
# Код получения значения из хеша объекта. Акцессор.
# 
::done_testing; }; subtest 'get' => sub { 
local ($::_g0 = do {$::construct->get}, $::_e0 = '$self->{%(name)s}'); ::ok $::_g0 eq $::_e0, '$::construct->get # \> $self->{%(name)s}' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## has
# Код проверки существования значения. Акцессор.
# 
::done_testing; }; subtest 'has' => sub { 
local ($::_g0 = do {$::construct->has}, $::_e0 = 'exists $self->{%(name)s}'); ::ok $::_g0 eq $::_e0, '$::construct->has # \> exists $self->{%(name)s}' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## clear
# Код удаления значения. Акцессор.
# 
::done_testing; }; subtest 'clear' => sub { 
local ($::_g0 = do {$::construct->clear}, $::_e0 = 'delete $self->{%(name)s}'); ::ok $::_g0 eq $::_e0, '$::construct->clear # \> delete $self->{%(name)s}' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## weaken
# Код ослабления ссылки. Акцессор.
# 
::done_testing; }; subtest 'weaken' => sub { 
local ($::_g0 = do {$::construct->weaken}, $::_e0 = 'Scalar::Util::weaken(%(get)s);'); ::ok $::_g0 eq $::_e0, '$::construct->weaken # \> Scalar::Util::weaken(%(get)s);' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## accessor_name
# Имя метода-акцессора. Акцессор.
# 
::done_testing; }; subtest 'accessor_name' => sub { 
local ($::_g0 = do {$::construct->accessor_name}, $::_e0 = '%(name)s'); ::ok $::_g0 eq $::_e0, '$::construct->accessor_name # \> %(name)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## reader_name
# Имя метода-ридера. Акцессор.
# 
::done_testing; }; subtest 'reader_name' => sub { 
local ($::_g0 = do {$::construct->reader_name}, $::_e0 = '_get_%(name)s'); ::ok $::_g0 eq $::_e0, '$::construct->reader_name # \> _get_%(name)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## writer_name
# Имя метода-райтера. Акцессор.
# 
::done_testing; }; subtest 'writer_name' => sub { 
local ($::_g0 = do {$::construct->writer_name}, $::_e0 = '_set_%(name)s'); ::ok $::_g0 eq $::_e0, '$::construct->writer_name # \> _set_%(name)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## predicate_name
# Имя метода-предиката. Акцессор.
# 
::done_testing; }; subtest 'predicate_name' => sub { 
local ($::_g0 = do {$::construct->predicate_name}, $::_e0 = 'has_%(name)s'); ::ok $::_g0 eq $::_e0, '$::construct->predicate_name # \> has_%(name)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## clearer_name
# Имя метода-очистителя. Акцессор.
# 
::done_testing; }; subtest 'clearer_name' => sub { 
local ($::_g0 = do {$::construct->clearer_name}, $::_e0 = 'clear_%(name)s'); ::ok $::_g0 eq $::_e0, '$::construct->clearer_name # \> clear_%(name)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## initer
# Код инициализации атрибута. Акцессор.
# 
::done_testing; }; subtest 'initer' => sub { 
local ($::_g0 = do {$::construct->initer}, $::_e0 = '%(initvar)s%(write)s'); ::ok $::_g0 eq $::_e0, '$::construct->initer # \> %(initvar)s%(write)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## not_specified
# Код инициализации, если значение не указано. Акцессор.
# 
::done_testing; }; subtest 'not_specified' => sub { 
local ($::_g0 = do {$::construct->not_specified}, $::_e0 = do {''}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->not_specified # -> \'\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## getter
# Код геттера в акцессоре. Акцессор.
# 
::done_testing; }; subtest 'getter' => sub { 
local ($::_g0 = do {$::construct->getter}, $::_e0 = '%(read)s'); ::ok $::_g0 eq $::_e0, '$::construct->getter # \> %(read)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## setter
# Код сеттера в акцессоре. По умолчанию: '%(write)s'.
# 
::done_testing; }; subtest 'setter' => sub { 
local ($::_g0 = do {$::construct->setter}, $::_e0 = '%(write)s'); ::ok $::_g0 eq $::_e0, '$::construct->setter # \> %(write)s' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## selfret
# Код возврата из сеттера. Акцессор.
# 
::done_testing; }; subtest 'selfret' => sub { 
local ($::_g0 = do {$::construct->selfret}, $::_e0 = '$self'); ::ok $::_g0 eq $::_e0, '$::construct->selfret # \> $self' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## add_attr($code, $unshift)
# Добавляет атрибут к акцессору.
# 
::done_testing; }; subtest 'add_attr($code, $unshift)' => sub { 
$::construct->add_attr(':bvalue');
local ($::_g0 = do {$::construct->{attr}}, $::_e0 = do {[':lvalue', ':bvalue']}); ::is_deeply $::_g0, $::_e0, '$::construct->{attr} # --> [\':lvalue\', \':bvalue\']' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
$::construct->add_attr(':a_value', 1);
local ($::_g0 = do {$::construct->{attr}}, $::_e0 = do {[':a_value', ':lvalue', ':bvalue']}); ::is_deeply $::_g0, $::_e0, '$::construct->{attr} # --> [\':a_value\', \':lvalue\', \':bvalue\']' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; un...

# 
# ## add_preset($code, $unshift)
# Добавляет код предустановки перед записью.
# 
::done_testing; }; subtest 'add_preset($code, $unshift)' => sub { 
$::construct->add_preset('die if $val < 0;', 1);
local ($::_g0 = do {$::construct->{preset}}, $::_e0 = do {'die if $val < 0;'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->{preset} # -> \'die if $val < 0;\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; un...

# 
# ## add_trigger($code, $unshift)
# Добавляет триггер после записи.
# 
::done_testing; }; subtest 'add_trigger($code, $unshift)' => sub { 
$::construct->add_trigger('$self->on_change;');
local ($::_g0 = do {$::construct->{trigger}}, $::_e0 = do {'$self->on_change;'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->{trigger} # -> \'$self->on_change;\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0...

# 
# ## add_cleaner($code, $unshift)
# Добавляет код очистки перед удалением.
# 
::done_testing; }; subtest 'add_cleaner($code, $unshift)' => sub { 
$::construct->add_cleaner('$self->{old} = $self->{attr};');
local ($::_g0 = do {$::construct->{cleaner}}, $::_e0 = do {'$self->{old} = $self->{attr};'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->{cleaner} # -> \'$self->{old} = $self->{attr};\'' or ::diag ::_struct_diff($::_g...

# 
# ## add_access($code, $unshift)
# Добавляет код в геттер перед чтением атрибута.
# 
::done_testing; }; subtest 'add_access($code, $unshift)' => sub { 
$::construct->add_access('die unless $self->{attr};');
local ($::_g0 = do {$::construct->{access}}, $::_e0 = do {'die unless $self->{attr};'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->{access} # -> \'die unless $self->{attr};\'' or ::diag ::_struct_diff($::_g0, $::_e0)...

# 
# ## add_release($code, $unshift)
# Добавляет код в геттер после чтения.
# 
::done_testing; }; subtest 'add_release($code, $unshift)' => sub { 
$::construct->add_release('$val = undef;');
local ($::_g0 = do {$::construct->{release}}, $::_e0 = do {'$val = undef;'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->{release} # -> \'$val = undef;\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef ...

# 
# ## initializer
# Генерирует код для инициализации фичи в конструкторе (`new`).
# 
::done_testing; }; subtest 'initializer' => sub { 

local ($::_g0 = do {$::construct->initializer}, $::_e0 = do {<< 'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->initializer # -> << \'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
		if (exists $value{my_feature}) {
			my $val = delete $value{my_feature};
			die if $val < 0;
			$self->{my_feature} = $val;
			$self->on_change;
		}
END

# 
# ## destroyer
# Генерирует код для деструктора.
# 
::done_testing; }; subtest 'destroyer' => sub { 
local ($::_g0 = do {$::construct->destroyer}, $::_e0 = do {<<'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->destroyer # -> <<\'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
		if (exists $self->{my_feature}) {
			eval {
				$self->{old} = $self->{attr};
			};
			warn $@ if $@;
		}
END

# 
# ## accessor
# Генерирует код акцессора.
# 
::done_testing; }; subtest 'accessor' => sub { 



local ($::_g0 = do {$::construct->accessor}, $::_e0 = do {<<'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->accessor # -> <<\'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
package My::Package {
	sub my_feature:a_value:lvalue:bvalue {
		if (@_>1) {
			my ($self, $val) = @_;
			die if $val < 0;
			$self->{my_feature} = $val;
			$self->on_change;
			$self
		} else {
			my ($self) = @_;
			die unless $self->{attr};
			my $val = $self->{my_feature};
			$val = undef;
			$val
		}
	}
}
END

# 
# ## reader
# Генерирует код геттера.
# 
::done_testing; }; subtest 'reader' => sub { 
local ($::_g0 = do {$::construct->reader}, $::_e0 = do {<<'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->reader # -> <<\'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
package My::Package {
	sub _get_my_feature {
		my ($self) = @_;
		die unless $self->{attr};
		my $val = $self->{my_feature};
		$val = undef;
		$val
	}
}
END

# 
# ## writer
# Генерирует код сеттера.
# 
::done_testing; }; subtest 'writer' => sub { 
local ($::_g0 = do {$::construct->writer}, $::_e0 = do {<<'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->writer # -> <<\'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
package My::Package {
	sub _set_my_feature {
		my ($self, $val) = @_;
		die if $val < 0;
		$self->{my_feature} = $val;
		$self->on_change;
		$self
	}
}
END

# 
# ## predicate
# Генерирует код предиката.
# 
::done_testing; }; subtest 'predicate' => sub { 
local ($::_g0 = do {$::construct->predicate}, $::_e0 = do {<<'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->predicate # -> <<\'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
package My::Package {
	sub has_my_feature {
		my ($self) = @_;
		exists $self->{my_feature}
	}
}
END

# 
# ## clearer
# Генерирует код очистителя.
# 
::done_testing; }; subtest 'clearer' => sub { 
local ($::_g0 = do {$::construct->clearer}, $::_e0 = do {<<'END'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::construct->clearer # -> <<\'END\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
package My::Package {
	sub clear_my_feature {
		my ($self) = @_;
		if (exists $self->{my_feature}) {
			$self->{old} = $self->{attr};
			delete $self->{my_feature}
		}
		$self
	}
}

t/aion/meta/feature.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::Meta::Feature - метаописатель фичи
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
use Aion::Meta::Feature;

our $feature = Aion::Meta::Feature->new("My::Package", "my_feature" => (is => 'rw'));

local ($::_g0 = do {$feature->stringify}, $::_e0 = "has my_feature => (is => 'rw') of My::Package"); ::ok $::_g0 eq $::_e0, '$feature->stringify  # => has my_feature => (is => \'rw\') of My::Package' or ::diag ::_string_diff($::_g0, $::_e0); undef $:...

# 
# # DESCRIPTION
# 
# Описывает фичу, которая добавляется в класс функцией `has`.
# 
# # METHODS
# 
# ## pkg
# Пакет, к которому относится фича.
# 
::done_testing; }; subtest 'pkg' => sub { 
local ($::_g0 = do {$::feature->pkg}, $::_e0 = do {"My::Package"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->pkg # -> "My::Package"' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## name
# Имя фичи.
# 
::done_testing; }; subtest 'name' => sub { 
local ($::_g0 = do {$::feature->name}, $::_e0 = do {"my_feature"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->name # -> "my_feature"' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## opt
# Хеш опций фичи.
# 
::done_testing; }; subtest 'opt' => sub { 
local ($::_g0 = do {$::feature->opt}, $::_e0 = do {{is => 'rw'}}); ::is_deeply $::_g0, $::_e0, '$::feature->opt # --> {is => \'rw\'}' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## has
# Массив опций фичи в виде пар ключ-значение.
# 
::done_testing; }; subtest 'has' => sub { 
local ($::_g0 = do {$::feature->has}, $::_e0 = do {['is', 'rw']}); ::is_deeply $::_g0, $::_e0, '$::feature->has # --> [\'is\', \'rw\']' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## construct
# Объект конструктора фичи.
# 
::done_testing; }; subtest 'construct' => sub { 
local ($::_g0 = do {ref $::feature->construct}, $::_e0 = 'Aion::Meta::FeatureConstruct'); ::ok $::_g0 eq $::_e0, 'ref $::feature->construct # \> Aion::Meta::FeatureConstruct' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## order ()
# Порядковый номер фичи в классе.
# 
::done_testing; }; subtest 'order ()' => sub { 
local ($::_g0 = do {$::feature->order}, $::_e0 = do {0}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->order # -> 0' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## required (;$bool)
# Флаг обязательности фичи в конструкторе (`new`).
# 
::done_testing; }; subtest 'required (;$bool)' => sub { 
$::feature->required(1);
local ($::_g0 = do {$::feature->required}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->required # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## excessive (;$bool)
# Флаг избыточности фичи в конструкторе (`new`). Если она там есть должно выбрасываться исключение.
# 
::done_testing; }; subtest 'excessive (;$bool)' => sub { 
$::feature->excessive(1);
local ($::_g0 = do {$::feature->excessive}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->excessive # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## isa (;Object[Aion::Type])
# Ограничение типа для значения фичи.
# 
::done_testing; }; subtest 'isa (;Object[Aion::Type])' => sub { 
use Aion::Type;

my $Int = Aion::Type->new(name => 'Int');

$::feature->isa($Int);
local ($::_g0 = do {$::feature->isa}, $::_e0 = do {$Int}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->isa # -> $Int' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## lazy (;$bool)
# Флаг ленивой инициализации.
# 
::done_testing; }; subtest 'lazy (;$bool)' => sub { 
$::feature->lazy(1);
local ($::_g0 = do {$::feature->lazy}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->lazy # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## builder (;$sub)
# Билдер значения фичи или `undef`.
# 
::done_testing; }; subtest 'builder (;$sub)' => sub { 
my $builder = sub {};
$::feature->builder($builder);
local ($::_g0 = do {$::feature->builder}, $::_e0 = do {$builder}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->builder # -> $builder' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## default (;$value)
# Значение по умолчанию для фичи.
# 
::done_testing; }; subtest 'default (;$value)' => sub { 
$::feature->default(42);
local ($::_g0 = do {$::feature->default}, $::_e0 = do {42}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->default # -> 42' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## trigger (;$sub)
# Обработчик события изменения значения фичи или `undef`.
# 
::done_testing; }; subtest 'trigger (;$sub)' => sub { 
my $trigger = sub {};
$::feature->trigger($trigger);
local ($::_g0 = do {$::feature->trigger}, $::_e0 = do {$trigger}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->trigger # -> $trigger' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## release (;$sub)
# Обработчик события чтения значения из фичи или `undef`.
# 
::done_testing; }; subtest 'release (;$sub)' => sub { 
my $release = sub {};
$::feature->release($release);
local ($::_g0 = do {$::feature->release}, $::_e0 = do {$release}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->release # -> $release' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## cleaner (;$sub)
# Обработчик события удаления фичи из объекта или `undef`.
# 
::done_testing; }; subtest 'cleaner (;$sub)' => sub { 
my $cleaner = sub {};
$::feature->cleaner($cleaner);
local ($::_g0 = do {$::feature->cleaner}, $::_e0 = do {$cleaner}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->cleaner # -> $cleaner' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## make_reader (;$bool)
# Флаг создания метода-ридера.
# 
::done_testing; }; subtest 'make_reader (;$bool)' => sub { 
$::feature->make_reader(1);
local ($::_g0 = do {$::feature->make_reader}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->make_reader # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## make_writer (;$bool)
# Флаг создания метода-райтера.
# 
::done_testing; }; subtest 'make_writer (;$bool)' => sub { 
$::feature->make_writer(1);
local ($::_g0 = do {$::feature->make_writer}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->make_writer # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## make_predicate (;$bool)
# Флаг создания метода-предиката.
# 
::done_testing; }; subtest 'make_predicate (;$bool)' => sub { 
$::feature->make_predicate(1);
local ($::_g0 = do {$::feature->make_predicate}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->make_predicate # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## make_clearer (;$bool)
# Флаг создания метода-очистителя.
# 
::done_testing; }; subtest 'make_clearer (;$bool)' => sub { 
$::feature->make_clearer(1);
local ($::_g0 = do {$::feature->make_clearer}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->make_clearer # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## new ($pkg, $name, @has)
# Конструктор фичи.
# 
::done_testing; }; subtest 'new ($pkg, $name, @has)' => sub { 
my $feature = Aion::Meta::Feature->new('My::Class', 'attr', is => 'ro', default => 1);
local ($::_g0 = do {$feature->pkg}, $::_e0 = do {"My::Class"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$feature->pkg # -> "My::Class"' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$feature->name}, $::_e0 = do {"attr"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$feature->name # -> "attr"' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {$feature->opt}, $::_e0 = do {{is => 'ro', default => 1}}); ::is_deeply $::_g0, $::_e0, '$feature->opt # --> {is => \'ro\', default => 1}' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## stringify ()
# Строковое представление фичи.
# 
::done_testing; }; subtest 'stringify ()' => sub { 
local ($::_g0 = do {$::feature->stringify}, $::_e0 = do {"has my_feature => (is => 'rw') of My::Package"}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->stringify # -> "has my_feature => (is => \'rw\') of My::Package"' or...

# 
# ## mk_property ()
# Создаёт акцессор, геттер, сеттер, предикат и очиститель свойства.
# 
::done_testing; }; subtest 'mk_property ()' => sub { 
package My::Package { use Aion }

$::feature->mk_property;

local ($::_g0 = do {!!My::Package->can('my_feature')}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '!!My::Package->can(\'my_feature\') # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## meta ()
# Возвращает код в виде текста для доступа к метаинформации фичи.
# 
::done_testing; }; subtest 'meta ()' => sub { 
local ($::_g0 = do {$::feature->meta}, $::_e0 = '$Aion::META{\'My::Package\'}{feature}{my_feature}'); ::ok $::_g0 eq $::_e0, '$::feature->meta # \> $Aion::META{\'My::Package\'}{feature}{my_feature}' or ::diag ::_string_diff($::_g0, $::_e0); undef $::...

# 
# ## stash ($key; $val)
# Доступ к хранилищу свойств для вызывающего пакета.
# 
::done_testing; }; subtest 'stash ($key; $val)' => sub { 
$::feature->stash('my_key', 'my_value');
local ($::_g0 = do {$::feature->stash('my_key')}, $::_e0 = do {'my_value'}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, '$::feature->stash(\'my_key\') # -> \'my_value\'' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef ...

# 
# ## compare ($other)
# 
# Сравнивает старую фичу с перезагружаемой. Если свойство `isa` указано и не совпадёт, то будет выброшено исключение.
# 
# # AUTHOR
# 
# Yaroslav O. Kosmina <dart@cpan.org>
# 

t/aion/meta/requires-any-function.pm  view on Meta::CPAN

use common::sense; use open qw/:std :utf8/;  use Carp 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;  BEGIN {     $SIG{__DIE__} = sub ...
# 
# use common::sense;
# 
# use Aion::Meta::Util qw//;
# 
# Aion::Meta::Util::create_getters(qw/pkg name/);
# 
# sub new {
#     my $cls = shift;
#     bless {@_}, ref $cls || $cls;

t/aion/meta/requires-any-function.pm  view on Meta::CPAN

# 
# =head2 new (%args)
# 
# Constructor.
# 
# =head2 compare (CodeRef|Undef $other)
# 
# Checks that C<$other> is a function.
# 
# 	my $any_function = Aion::Meta::AnyFunction->new;
# 	eval { $any_function->compare(undef) }; $@  # ~> .3
# 
# =head1 AUTHOR
# 
# Yaroslav O. Kosmina L<mailto:dart@cpan.org>
# 
# =head1 LICENSE
# 
# âš– B<GPLv3>
# 
# =head1 COPYRIGHT

t/aion/meta/requires-any-function.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::Meta::RequiresAnyFunction - определяет любую функцию, которая должна быть в модуле
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
use Aion::Meta::RequiresAnyFunction;

my $any_function = Aion::Meta::RequiresAnyFunction->new(
	pkg => 'My::Package', name => 'my_function'
);

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

# 
# # DESCRIPTION
# 
# Создаётся в `requires fn1, fn2...` и при инициализации класса проверяется, что такая функция в нём была объявлена через `sub` или `has`.
# 
# # SUBROUTINES
# 
# ## new (%args)
# 
# Конструктор.
# 
# ## compare ($other)
# 
# Проверяет, что `$other` является функцией.
# 
::done_testing; }; subtest 'compare ($other)' => sub { 
my $any_function = Aion::Meta::RequiresAnyFunction->new(pkg => 'My::Package', name => 'my_function');
::like scalar do {eval { $any_function->compare(undef) }; $@}, qr{Requires my_function of My::Package}, 'eval { $any_function->compare(undef) }; $@  # ~> Requires my_function of My::Package'; undef $::_g0; undef $::_e0;

# 
# ## pkg ()
# 
# Возвращает имя пакета, в котором объявлена функция.
# 
::done_testing; }; subtest 'pkg ()' => sub { 
my $any_function = Aion::Meta::RequiresAnyFunction->new(pkg => 'My::Package');
local ($::_g0 = do {$any_function->pkg}, $::_e0 = "My::Package"); ::ok $::_g0 eq $::_e0, '$any_function->pkg  # => My::Package' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## name ()
# 
# Возвращает имя функции.
# 
::done_testing; }; subtest 'name ()' => sub { 
my $any_function = Aion::Meta::RequiresAnyFunction->new(name => 'my_function');
local ($::_g0 = do {$any_function->name}, $::_e0 = "my_function"); ::ok $::_g0 eq $::_e0, '$any_function->name  # => my_function' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# ## stringify ()
# 
# Возвращает строковое представление объекта.
# 
# # AUTHOR
# 
# Yaroslav O. Kosmina <dart@cpan.org>
# 

t/aion/meta/requires-feature.pm  view on Meta::CPAN

use common::sense; use open qw/:std :utf8/;  use Carp 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;  BEGIN {     $SIG{__DIE__} = sub ...
# 
# use common::sense;
# 
# use Aion::Meta::Util qw//;
# use List::Util qw/pairmap/;
# use Scalar::Util qw/looks_like_number reftype blessed refaddr/;
# 
# Aion::Meta::Util::create_getters(qw/pkg name opt has/);
# 
# #  Конструктор

t/aion/meta/requires-feature.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::Meta::RequiresFeature - требование фичи для интерфейсов
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
use Aion::Types qw(Str);
use Aion::Meta::RequiresFeature;
use Aion::Meta::Feature;

t/aion/meta/requires-feature.t  view on Meta::CPAN

my $req = Aion::Meta::RequiresFeature->new(
	'My::Package', 'name', is => 'rw', isa => Str);

my $feature = Aion::Meta::Feature->new(
	'Other::Package',
	'name', is => 'rw', isa => Str,
	default => 'default_value');

$req->compare($feature);

local ($::_g0 = do {$req->stringify}, $::_e0 = "req name => (is => 'rw', isa => Str) of My::Package"); ::ok $::_g0 eq $::_e0, '$req->stringify  # => req name => (is => \'rw\', isa => Str) of My::Package' or ::diag ::_string_diff($::_g0, $::_e0); unde...

# 
# # DESCRIPTION
# 
# С помощью `req` создаёт требование к фиче которая будет описана в модуле к которому будет подключена роль или который унаследует абстракÑ...
# 
# Проверяться будут только указанные аспекты в фиче.
# 
# # SUBROUTINES
# 

t/aion/meta/subroutine.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::Meta::Subroutine - описывает функцию с сигнатурой
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
use Aion::Types qw(Int);
use Aion::Meta::Subroutine;

my $subroutine = Aion::Meta::Subroutine->new(
	pkg => 'My::Package',
	subname => 'my_subroutine',
	signature => [Int, Int],
	referent => undef,
);

local ($::_g0 = do {$subroutine->stringify}, $::_e0 = "my_subroutine(Int => Int) of My::Package"); ::ok $::_g0 eq $::_e0, '$subroutine->stringify  # => my_subroutine(Int => Int) of My::Package' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; ...

# 
# # DESCRIPTION
# 
# Служит для объявления требуемой функции в интерфейсах и обстрактных классах.
# При этом `referent ~~ Undef`.
# 
# А так же создаёт функцию-обёртку проверяющую сигнатуру.
# 
# # SUBROUTINES

t/aion/meta/util.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::Meta::Util - вспомогательные функции для создания мета-данных
# 
# # SYNOPSIS
# 
subtest 'SYNOPSIS' => sub { 
package My::Meta::Class {
	use Aion::Meta::Util;
	
	create_accessors qw/age/;
	create_getters qw/name/;
}

my $class = bless {name => 'car'}, 'My::Meta::Class';

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

local ($::_g0 = do {$class->name}, $::_e0 = "car"); ::ok $::_g0 eq $::_e0, '$class->name  # => car' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
::like scalar do {eval { $class->name('auto') }; $@}, qr{name is ro}, 'eval { $class->name(\'auto\') }; $@ # ~> name is ro'; undef $::_g0; undef $::_e0;

# 
# # DESCRIPTION
# 
# В мета-классах поддерживающих создание фич и сигнатур функций (т.е. внутреннюю кухню Aion) требуется своя небольшая реализация, которую и ...
# 
# # SUBROUTINES
# 
# ## create_getters (@getter_names)
# 

t/aion/meta/util.t  view on Meta::CPAN

# 
# Создаёт геттер-сеттеры.
# 
# ## subref_is_reachable ($subref)
# 
# Проверяет, имеет ли подпрограмма тело.
# 
::done_testing; }; subtest 'subref_is_reachable ($subref)' => sub { 
use Aion::Meta::Util;

local ($::_g0 = do {subref_is_reachable(\&nouname)}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'subref_is_reachable(\&nouname)             # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $:...
local ($::_g0 = do {subref_is_reachable(UNIVERSAL->can('isa'))}, $::_e0 = do {""}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'subref_is_reachable(UNIVERSAL->can(\'isa\')) # -> ""' or ::diag ::_struct_diff($::_g0, $::_e0); undef $:...
local ($::_g0 = do {subref_is_reachable(sub {})}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'subref_is_reachable(sub {})                # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {subref_is_reachable(\&CORE::exit)}, $::_e0 = do {1}); ::ok defined($::_g0) == defined($::_e0) && $::_g0 eq $::_e0, 'subref_is_reachable(\&CORE::exit)          # -> 1' or ::diag ::_struct_diff($::_g0, $::_e0); undef $::_g0; undef $...

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

local ($::_g0 = do {Aion::Meta::Util::val_to_str(qr/^[A-Z]/)}, $::_e0 = "qr/^[A-Z]/u"); ::ok $::_g0 eq $::_e0, 'Aion::Meta::Util::val_to_str(qr/^[A-Z]/)   # => qr/^[A-Z]/u' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;
local ($::_g0 = do {Aion::Meta::Util::val_to_str(qr/^[A-Z]/i)}, $::_e0 = "qr/^[A-Z]/ui"); ::ok $::_g0 eq $::_e0, 'Aion::Meta::Util::val_to_str(qr/^[A-Z]/i)   # => qr/^[A-Z]/ui' or ::diag ::_string_diff($::_g0, $::_e0); undef $::_g0; undef $::_e0;

# 
# # AUTHOR
# 
# Yaroslav O. Kosmina <dart@cpan.org>
# 
# # LICENSE
# 
# âš– **GPLv3**
# 



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