Я занимаюсь с Moose около семи месяцев, а Perl немного длиннее, но не могу понять, как вы можете построить несколько атрибутов в классе, просто поместив один аргумент для каждого, вместо этого всего их хэш. Я много раз искал документацию и веб-сайт, но я либо искал неправильные слова, либо что-то пропустил.Moose объекты конструкции из одиночных аргументов
Я адаптировал дизайн к более универсальному. При следующей базовой настройки:
package First;
use Moose;
use Second::Type1;
use Second::Type2;
has 'type1' => (
is => 'rw',
isa => 'Second::Type1',
default => sub {Second::Type1->new(name => 'random')}
);
has 'type2' => (
is => 'rw',
isa => 'Second::Type2',
default => sub {Second::Type2->new(name => 'random')}
);
package Second::Type1;
use Moose;
use This;
has 'name' => (
is => 'rw',
isa => 'Str',
required => 1,
);
has 'this' => (
is => 'rw',
isa => 'This',
default => sub {This->new()}
);
# package has more attributes, but you get the idea
__PACKAGE__->meta->make_immutable();
no Moose;
1;
package Second::Type2;
use Moose;
use That;
has 'name' => (
is => 'rw',
isa => 'Str',
required => 1,
);
has 'that' => (
is => 'rw',
isa => 'That',
default => sub {That->new()}
);
# package has more attributes, but you get the idea
__PACKAGE__->meta->make_immutable();
no Moose;
1;
Я хочу, чтобы иметь возможность построить первый, говоря:
use First;
my $first = First->new(type1 => 'foo', type2 => 'bar');
где «Foo» равно значению для второго :: атрибут «имя» Type1 в и ' bar 'равно значению для атрибута «name» второго :: Type2.
Теперь, что касается моего собственного решения, я (успешно) сделал Moose :: Role, который содержит только «вокруг BUILDARGS», а затем использует класс Factory (содержимое которого здесь не имеет значения IMO) :
package Role::SingleBuildargs;
use Moose::Role;
use Factory::Second;
requires 'get_supported_args';
around BUILDARGS => sub {
my ($class, $self, %args) = @_;
my @supported_args = $self->get_supported_args;
my $factory = Factory::Second->new();
my @errors =();
foreach my $arg (sort {$a cmp $b} keys %args) {
if (grep {$_ eq $arg} @supported_args) {
my $val = $args{$arg};
if (!ref $val) { # passed scalar init_arg
print "$self (BUILDARGS): passed scalar\n";
print "Building a Second with type '$arg' and name '$val'\n";
$args{$arg} = $factory->create(type => $arg, name => $val)
} elsif (ref $val eq 'HASH') { # passed hashref init_arg
print "$self (BUILDARGS): passed hashref:\n";
my %init_args = %$val;
delete $init_args{name} unless $init_args{name};
$init_args{type} = $arg;
$args{$arg} = $factory->create(%init_args);
} else { # passed another ref entirely
print "$self (BUILDARGS): cannot handle reference of type: ", ref $val, "\n";
die;
}
} else {
push @errors, "$self - Unsupported attribute: '$arg'";
}
}
if (@errors) {
print join("\n", @errors), "\n";
die;
}
return $self->$class(%args);
};
no Moose;
1;
, а затем я использую эту роль в первом классе и других классах, таких как First.
Я также попытался принуждении через:
package Role::Second::TypeConstraints;
use Moose::Util::TypeConstraints
subtype 'SecondType1', as 'Second::Type1';
subtype 'SecondType2', as 'Second::Type2';
coerce 'SecondType1', from 'Str', via {Second::Type1->new(name => $_};
coerce 'SecondType2', from 'Str', via {Second::Type2->new(name => $_};
no Moose::Util::TypeConstraints;
1;
и модифицировали первый пакет (листинг только изменения):
use Role::Second::TypeConstraints;
has 'type1' => (
isa => 'SecondType1',
coerce => 1,
);
has 'type2' => (
isa => 'SecondType2',
coerce => 1,
);
Это, однако, не работает. Если бы кто-то мог объяснить, почему это было бы здорово.
Что касается фактического вопроса: что является лучшим способом получить такое поведение в ваших классах? Нет ли лучшего способа, чем изменение BUILDARGS, или я пропустил что-то (о Moose :: Util :: TypeConstraints, возможно)? TMTOWTDI и все, но мои не кажутся эффективными вообще.
EDIT: отредактированы для последовательности (вперемешку родовые имена классов)
Я делал такие вещи в прошлом, используя принуждение. Не могу понять, почему ваша существующая установка принуждения не делает этого. Вы вспомнили, что обычно является основным камнем преткновения, который добавляет метасимволу принуждения к атрибутам, в которых вы хотите добиться принуждения. Я предлагаю настойчиво с принуждением. – zgpmax
Это именно то, для чего «BUILDARGS». – simbabque