Reputation: 11243
Suppose I want a class like this:
package Restraint;
use Moose;
has ball => (
is => 'ro',
does => 'Heavy',
);
has chain => (
is => 'ro',
does => 'Lockable',
);
has ball_class => (
is => 'ro',
isa => 'Str',
);
has chain_class => (
is => 'ro',
isa => 'Str',
);
1;
Now I want to instantiate the class like:
my $r = Restraint->new(
ball_class = 'Ball',
chain_class = 'Chain',
);
both arguments being mandatory.
I also want to instantiate both ball_class
and chain_class
during construction and assign them to corresponding attributes so that finally I can e.g. $r->ball->lift
or $r->chain->lock
etc.
How should I do that?
Upvotes: 2
Views: 147
Reputation: 22893
Just mark them both "required" - see Moose::Manual::Attributes
That's not going to do anything for "ball" or "chain" though. There's no connection.
You could set up ball/chain with lazy builders which would reference your classnames (see the Moose Manual again).
I'd probably just make the objects required and pass them in directly though:
my $r = Restraint->new(
ball => CannonBall->new(...),
chain => IronChain->new(...)
);
OK - you don't want to pass in objects. In that case you want lazy builders. Mark the ball as lazy and give it a builder and Moose will call the builder when the ball is first used.
http://metacpan.org/pod/Moose::Manual::Attributes
http://metacpan.org/pod/Moose::Cookbook::Basics::Recipe3
Do take the time to read the moose documentation - there's a lot of it, but it's quite well written and covers plenty of features. Lots of examples.
package Restraint;
use Moose;
has ball => (
is => 'ro',
does => 'Heavy',
lazy => 1,
builder => '_build_ball'
);
has ball_class => (
is => 'ro',
required => 1
);
sub _build_ball {
my $self = shift;
my $ball_class = $self->ball_class;
return $ball_class->new();
}
Upvotes: 3
Reputation: 11243
Using BUILD
for instantiation while setting required
only for *_class
attributes seems to work to some extent, except that:
ball
and chain
read-writeCode:
package Restraint;
use Moose;
has ball => (
is => 'rw',
does => 'Heavy',
);
has chain => (
is => 'rw',
does => 'Lockable',
);
has ball_class => (
is => 'ro',
isa => 'Str',
required => 1,
);
has chain_class => (
is => 'ro',
isa => 'Str',
required => 1,
);
sub BUILD {
my $self = shift;
my $ball = $self->ball_class->new();
$self->ball( $ball );
my $chain = $self->chain_class->new();
$self->chain( $chain );
}
1;
It's not a big sacrifice for now, but I still wonder if there is more correct way, though.
Upvotes: 1