我想使用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()
被调用之前不会运行。
我认为我需要的是一个具有角色的新课程。我可能会过度思考这个。
答案 0 :(得分:1)
您可以创建组成存储行为的新角色(JSONFiler
),然后使用with_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 JSONFiler;
use Moose::Role;
use MooseX::Storage;
with Storage(format => 'JSON', io => 'File');
package main;
use warnings;
use strict;
use feature 'say';
## create a new Note class with the Storage traits
my $note_class = Note->with_traits('JSONFiler');
## make a new note and store it
my $note = $note_class->new(title => 'Note 1');
$note->body("Here is the note");
$note->store($note->title . ".json");
## load the stored note
undef $note;
$note = $note_class->load("Note 1.json");
say $note->body;