У меня есть базовый класс и десяток производных классов. Все производные классы, кроме одного, требуют атрибута с именем 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;
Это работает, но есть ли лучший способ добиться того, чего я хочу?