Aion
view release on metacpan or search on metacpan
lib/Aion/Meta/RequiresFeature.pm view on Meta::CPAN
package Aion::Meta::RequiresFeature;
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/);
# ÐонÑÑÑÑкÑоÑ
sub new {
my ($cls, $pkg, $name, @has) = @_;
bless {pkg => $pkg, name => $name, opt => {@has}, has => \@has}, ref $cls || $cls;
}
# СÑÑоковое пÑедÑÑавление ÑиÑи
sub stringify {
my ($self) = @_;
my $has = join ', ', pairmap { "$a => ${\
Aion::Meta::Util::val_to_str($b)
}" } @{$self->{has}};
return "req $self->{name} => ($has) of $self->{pkg}";
}
# СÑÐ°Ð²Ð½Ð¸Ð²Ð°ÐµÑ Ñ ÑиÑей, но ÑолÑко знаÑÐµÐ½Ð¸Ñ ÐºÐ¾ÑоÑÑе еÑÑÑ Ð² ÑÑой
sub compare {
my ($self, $feature) = @_;
die "Requires ${\$self->stringify}" unless UNIVERSAL::isa($feature, 'Aion::Meta::Feature');
for my $key (keys %{$self->{opt}}) {
my $value = $self->{opt}{$key};
my $feature_value = $feature->{opt}{$key};
die "Feature mismatch ($key => ${\
Aion::Meta::Util::val_to_str($value)
} != ${\
Aion::Meta::Util::val_to_str($feature_value)
}) with ${\$self->stringify}"
unless _deep_equal($value, $feature_value);
}
}
# СÑÐ°Ð²Ð½Ð¸Ð²Ð°ÐµÑ Ð´Ð²Ð° знаÑениÑ
sub _deep_equal {
my ($value, $other_value) = @_;
if (blessed $value) {
return "" unless blessed $other_value;
if (overload::Method($value, '==')) {
return "" unless $value == $other_value;
}
elsif (overload::Method($value, 'eq')) {
return "" unless $value eq $other_value;
}
else {
return "" unless refaddr $value == refaddr $other_value;
}
}
elsif (looks_like_number($value)) {
return "" unless looks_like_number($other_value) && $value == $other_value;
}
elsif (reftype $value eq 'ARRAY') {
for(my $i = 0; $i <= $#$value; $i++) {
return "" unless _deep_equal($value->[$i], $other_value->[$i]);
}
}
elsif (reftype $value eq 'HASH') {
for my $k (keys %$value) {
return "" unless exists $other_value->{$k} && _deep_equal($value->{$k}, $other_value->{$k});
}
}
elsif (reftype $value eq 'SCALAR') {
return "" unless reftype $other_value eq 'SCALAR' && _deep_equal($$value, $$other_value);
}
elsif (reftype $value eq 'CODE') {
return "" unless reftype $other_value eq 'CODE' && refaddr $value == refaddr $other_value;
}
else {
return "" if $value ne $other_value;
}
return 1;
}
1;
__END__
=encoding utf-8
=head1 NAME
Aion::Meta::RequiresFeature - feature requirement for interfaces
=head1 SYNOPSIS
use Aion::Types qw(Str);
use Aion::Meta::RequiresFeature;
use Aion::Meta::Feature;
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);
$req->stringify # => req name => (is => 'rw', isa => Str) of My::Package
=head1 DESCRIPTION
Using C<req> creates a requirement for a feature that will be described in the module to which the role will be connected or which will inherit the abstract class.
Only the specified aspects in the feature will be checked.
=head1 SUBROUTINES
( run in 1.765 second using v1.01-cache-2.11-cpan-39bf76dae61 )