Доступ к MooseX::ClassAttribute в Moose::Role

Вот загадка. Я использую Moose::Role в качестве интерфейса, где конкретные классы должны реализовать необходимые построители атрибутов, определенные ролью. Роль также определяет некоторые методы, которые выполняют логику над атрибутами. Вот уменьшенная версия того, что я пытаюсь сделать.

package Parent;
use Moose::Role;
requires '_build_permission_level';

has 'permission_level' => (
    is => 'ro',
    isa => Int,
    lazy_build => 1,
);

use constant {
    LEVEL1 = 1,
    LEVEL2 = 2,
    LEVEL3 = 3,
};

sub can_do_action {
    my $self = shift;
    return $self->permission_level() >= LEVEL2;
}

package Child;
use Moose;
with 'Parent';

sub _build_permission_level { return Parent->LEVEL3; }

Очевидно, у меня много дочерних классов с разными уровнями разрешений. Теперь это работает, за исключением того, что это ужасно неэффективно. Все дочерние экземпляры всегда будут иметь один и тот же уровень разрешений, но мне нужно создать его экземпляр только для того, чтобы спросить, может ли он выполнить действие. Запустив это массово 10 000 раз, вы получите картину.

Поэтому вместо этого я хотел бы сделать уровень разрешения атрибутом класса. Решает проблему эффективности по-лосячьи. Обратите внимание, что Permission_level больше не требует $self.

package Parent;
use Moose::Role;
use MooseX::ClassAttribute;
requires '_build_permission_level';

class_has 'permission_level' => (
    is => 'ro',
    isa => Int,
    builder => '_build_permission_level',
);

use constant {
    LEVEL1 = 1,
    LEVEL2 = 2,
    LEVEL3 = 3,
};

sub can_do_action {
    return permission_level() >= LEVEL2;
}

package Child;
use Moose;
with 'Parent';

sub _build_permission_level { return Parent->LEVEL3; }

Это умирает с неопределенной ошибкой подпрограммы, не может найти Parent::permission_level. Таким образом, родитель ничего не знает об уровне разрешения. Действительно? Я смущен тем, как он не может получить доступ к своему собственному атрибуту класса. Я должен упустить что-то очень простое. Но, что еще более важно, как я должен заставить Родителя обеспечивать логику для атрибута класса, который предоставляет Ребенок?


person Mike Monkiewicz    schedule 24.05.2012    source источник


Ответы (1)


Ошибка указывает на то, что во время компиляции не существует подпрограммы Parent::permission_level. И это правда: has и class_has — это конструкции времени выполнения; подпрограмма еще не создана, когда вызов в can_do_action компилируется.

Настоящая проблема заключается в том, что вы используете неправильный синтаксис для вызова метода класса. Перепишите can_do_action таким образом:

sub can_do_action {
    my ($class) = @_;

    return $class->permission_level >= LEVEL2;
}

и он должен работать нормально. В отличие от обычного вызова функции, вызов метода не разрешается до времени выполнения, после чего Parent::permission_level будет существовать.

person darch    schedule 24.05.2012
comment
Да, это была простая вещь, которую мне не хватало. Спасибо! - person Mike Monkiewicz; 24.05.2012