Moose: переопределить `обязательность` атрибута в производном классе - PullRequest
3 голосов
/ 03 июня 2011

У меня есть базовый класс и десяток производных классов. Все производные классы, кроме одного, требуют атрибута с именем key. Так что я мог бы добавить его к одиннадцати производным классам и оставить двенадцатый в покое.

Однако, поскольку лень - то, чем она является, я хотел бы добавить атрибут в базовый класс, избегая, таким образом, повторения объявления одиннадцать раз и добавляя, что я считаю, последовательность и простота.

Теперь это создает проблему для одного класса, для которого не требуется атрибут key. Обратите внимание, что нет никакого вреда, если этот класс имеет этот атрибут, но он не требует его.

Моя идея состояла в том, чтобы решить эту проблему, используя метод флага is_strict, который будет вызываться из BUILDARGS, чтобы решить, требуется ли key или нет. Вот простой сценарий, чтобы проиллюстрировать это (хорошо, я перевернул понятие, атрибут key требуется только в одном случае (а не во всех, кроме одного), но эта инверсия по-прежнему затрагивает проблему):

#!perl
package Bla;
use Moose;
use Carp ();
has grop => is => 'ro', isa => 'Str'; # optional
has key  => is => 'ro', isa => 'Int'; # required in all but one cases
# required => should depend on $class->is_strict;
sub is_strict { 0 } # not strict by default as per this base class
# imagine a bunch of other stuff here shared by all derived classes
around BUILDARGS => sub {
    my $orig = shift;
    my $class = shift;
    my $args = @_ == 1 ? shift : { @_ };
    Carp::croak 'key missing'
        if not exists $args->{key}
        and $class->is_strict;
    return $class->$orig( @_ );
};
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Eins;
use Moose; extends 'Bla';
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Zwei;
use Moose; extends 'Bla';
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Drei;
use Moose; extends 'Bla';
override is_strict => sub { 1 }; # but here it is required
no Moose; __PACKAGE__->meta->make_immutable;

package main;
use Test::More;
use Test::Exception;
lives_ok  { Bla::Eins->new };
lives_ok  { Bla::Zwei->new };
throws_ok { Bla::Drei->new } qr/key missing/;
lives_ok  { Bla::Drei->new( key => 99 ) };
done_testing;

Это работает, но есть ли лучший способ добиться того, чего я хочу?

Ответы [ 2 ]

6 голосов
/ 03 июня 2011

Хорошо, я немного глуп, что не попробовал самое очевидное решение, просто переопределил определение атрибута в производном классе, где required ness отличается от значения по умолчанию. Вот и мы:

#!perl
package Bla;
use Moose;
use Carp ();
has grop => is => 'ro', isa => 'Str'; # optional
has key  => is => 'ro', isa => 'Int'; # required in all but one cases
# imagine a bunch of other stuff here shared by all derived classes
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Eins;
use Moose; extends 'Bla';
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Zwei;
use Moose; extends 'Bla';
no Moose; __PACKAGE__->meta->make_immutable;

package Bla::Drei;
use Moose; extends 'Bla';
# prefix an attribute you're overriding with a "+" sign
has '+key' => is => 'ro', isa => 'Int', required => 1;
no Moose; __PACKAGE__->meta->make_immutable;

package main;
use Test::More;
use Test::Exception;
lives_ok  { Bla::Eins->new };
lives_ok  { Bla::Zwei->new };
throws_ok { Bla::Drei->new } qr/\bkey\b.*\brequired\b/;
lives_ok  { Bla::Drei->new( key => 99 ) };
done_testing;

Тем не менее, я благодарен за все отзывы, поскольку этот Mooseland менее хорошо зачарован, чем объектные системы на других языках.

Ах, и я видел, что вы должны префикс определения атрибута, который вы переопределяете, с +, поэтому Moose будет жалко croak, если указанный атрибут не найден в родительском классе, добавление безопасности и согласованности в ваш код. Я обновил свой пример кода соответственно.

1 голос
/ 23 сентября 2014

Вместо использования has '+key' => (requires => 1) вы можете поместить requires=> 1 в оригинал и использовать has '+key' => (requires => 0) для его выключения. В первоначальном запросе было 11 обязательных и только одно необязательное, так что это означало бы, что только одно определение нуждается в перегрузке, а остальные 11 могут принять его без изменений.

...