How can I set up a bunch of attribute builders in a Moose object?
I have the following five Moose attributes:
has ['summary_file', 'html_file', 'url1', 'url2', 'txt_file'] => (
is => 'rw',
isa => 'Str',
required => 0,
lazy => 1,
default => sub { confess "Attribute not set"; },
);
I would like to:
- Make each of them use its own builder (e.g. set 开发者_JAVA技巧
'summary_file'
use_build_summary_file
, etc.) - Make the default
confess
sub state which (uninitialized) attribute was called (e.g."Attribute 'summary_file' not set"
).
I can accomplish the above by writing five separate has
's, but perhaps there's a more compact way?
You could do something the like following (new working example after your "does not work" comment below):
package My::Class;
use Moose;
use namespace::autoclean;
for my $attr (qw(x y)) {
has $attr => (
is => 'rw',
isa => 'Str',
required => 0,
lazy => 1,
builder => "_build_$attr",
);
}
sub _build_x { rand }
sub _build_y { rand }
__PACKAGE__->meta->make_immutable;
package main;
use strict; use warnings;
my $o = My::Class->new;
print $o->$_, "\n" for qw(x y);
Note that you cannot specify both a default
and a builder
.
@Oesor points out in a comment something I forgot:
has ['summary_file', 'html_file', 'url1', 'url2', 'txt_file'] => (
is => 'rw',
isa => 'Str',
required => 0,
lazy_build => 1,
);
If you're looking for an attribute to throw an exception on access when it does not have a value set, look at MooseX::LazyRequire.
If you're looking for a builder to throw an warning if it's called, include that statement in the builder method... OR wrap the accessor/reader method to do that. (e.g. "before 'attribute_name' => sub { ...complain... };
")
If you're looking for an way to specify builder methods to an attribute using the same naming convention lazy_build does, see MooseX::AttributeShortcuts (supporting 'builder => 1
' as 'builder => "_build_${attribute_name}"
').
精彩评论