Я хочу использовать параметризованную роль MooseX::Storage
, но я также хочу разрешить предоставление параметров через конструктор. Вот «статическая» версия, которая работает как положено:
package Note;
use Moose;
use namespace::autoclean;
use MooseX::StrictConstructor;
use MooseX::Storage;
has title => (is => 'ro', isa => 'Str');
has body => (is => 'rw', isa => 'Str');
with Storage(format => 'JSON', io => 'File');
__PACKAGE__->meta->make_immutable;
package main;
use warnings;
use strict;
use feature 'say';
## make a new note and store it
my $note = Note->new(title => 'Note 1');
$note->body("Here is the note");
$note->store($note->title . ".json");
## load the stored note
undef $note;
$note = Note->load("Note 1.json");
say $note->body;
Но я хочу сделать параметры хранилища динамическими. Я думал об использовании черты, как описано в MooseX :: Traits , что-то вроде этого:
package Note;
use Moose;
use namespace::autoclean;
use MooseX::StrictConstructor;
has title => (is => 'ro', isa => 'Str');
has body => (is => 'rw', isa => 'Str');
with 'MooseX::Traits';
__PACKAGE__->meta->make_immutable;
package main;
use warnings;
use strict;
use feature 'say';
use MooseX::Storage;
## make a new note; set the storage format dynamically
my $note = Note->with_traits(Storage => {format => 'JSON', io => 'File'})->new(title => 'Note 1');
$note->body("Here is the note");
$note->store($note->title . ".json");
## load the stored note
undef $note;
$note = Note->load("Note 1.json");
say $note->body;
Но я получаю ошибку:
Can't locate Storage.pm in @INC
Я пытался use MooseX::Storage
в обоих классах и т. Д. Я смотрел на meta->apply
и apply_all_roles
, но ни один из них, похоже, не подходит для параметризованных ролей.
Есть кое-что, чего я не понимаю в параметризованных ролях. Мне интересно, должен ли я обернуть параметризованную роль в непараметрическую роль (например, StorageWithJSONFile
) и использовать эту черту. Это был бы хороший подход?
Как правильно установить параметры этой роли при строительстве объекта? Или есть лучший способ придать объекту параметризованную роль?
Редактировать: Я узнал, что функция Storage()
, которая MooseX::Storage
экспортирует , возвращает список ролей, когда она вызывается. Это кое-что прояснило для меня, поэтому я попробую это:
package Note;
use Moose;
use namespace::autoclean;
use MooseX::StrictConstructor;
use MooseX::Storage;
use Moose::Util 'apply_all_roles';
has title => (is => 'ro', isa => 'Str');
has body => (is => 'rw', isa => 'Str');
has storage => (is => 'ro', isa => 'HashRef[Str]');
sub BUILD {
my ($self) = @_;
apply_all_roles($self, Storage(%{$self->storage}));
}
__PACKAGE__->meta->make_immutable;
package main;
use warnings;
use strict;
use feature 'say';
## make a new note and store it: this works!
my $note = Note->new(title => 'Note 1', storage => {format => 'JSON', io => 'File'});
$note->body("Here is the note");
$note->store($note->title . ".json");
## load the stored note: this does not work: Can't locate object method "load" via package "Note" at test4.pl line 32.
undef $note;
$note = Note->load("Note 1.json"); ## where are the roles?
say $note->body;
Содержимое Note 1.json
:
{"__CLASS__":"Moose::Meta::Class::__ANON__::SERIAL::2","body":"Here is the note","storage":{"format":"JSON","io":"File"},"title":"Note 1"}
Кажется, у меня проблема с куриным яйцом: load()
применяется к классу после запуска BUILD
; BUILD
не будет работать, пока не будет вызван load()
. 1040 *
Я думаю, что мне нужен новый класс с составленной ролью. Возможно, я слишком обдумываю это.