New & Improved: MooseX::Role::BuildInstanceOf
New & Improved: MooseX::Role::BuildInstanceOf
Okay, so MooseX::Role::BuildInstanceOf is not one of my modules. And while I submited the patch, the feature itself was born out of fREW’s DBIx::Class::DeploymentHandler. So, in all this, my role was at best to be the pollinator agent between two beautiful flowers. But, hey, it’s not like a little bit of noise is going to hurt any of the involved parties, sooo… let’s see what the buzz’s about.
Insanely Quick Intro to MooseX::Role::BuildInstanceOf
MooseX::Role::BuildInstanceOf is a Moose module that aims at reducing the amount of boilerplate code needed for dealing with sub-objects. It’s a little meta-scary at first, but once one understanding settles in, it’s humongously handy. Without going into the details, with that module, you can turn that chunk of code:
package MyShip;
use Moose;
has engine => (
is => 'ro',
lazy_build => 1,
);
has engine_args => (
isa => 'ArrayRef',
is => 'ro',
);
sub _build_engine {
my $self = shift;
return MyShip::Engine->new(
@{ $self->engine_args || [ fuel => 100 ] },
max_speed => 10,
);
}
1;
into
package MyShip;
use Moose;
with 'MooseX::Role::BuildInstanceOf' => {
target => '::Engine',
args => [ fuel => 100 ],
fixed_args => [ max_speed => 10 ],
};
1;
Both versions will do just what you think it will do when you write
# damned Ferengies never fill up the tank
my $warbird = MyShip->new( engine_args => [ fuel => 20 ] );
There is a lot more to MooseX::Role::BuildInstanceOf than that, but we can agree that it’s already pretty sweet.
So, What’s New?
In the last few days, I’ve been deep-diving into DBIx::Class::DeploymentHandler. Within that distribution, fREW kinda rolled out a module similar to MooseX::Role::BuildInstanceOf: DBIx::Class::DeploymentHandler::WithApplicatorDumple. It is acknowledged in the source of the module that its implementation is a little on the ghetto side, and should probably be refactored with Role::subsystem or, ah AH!, MooseX::Role::BuildInstanceOf.
Me, eternal meddler, couldn’t
resist looking into that, and quickly saw that WithApplicatorDumple
had
something that MX::R::BIO
was missing: the ability to automatically
push down to the sub-objects some attributes of the main object. Very handy,
that. So I cracked my knuckles, went to work… and by now the code
package MyShip;
use Moose;
has captain => ( is => 'ro' );
has intercom => (
is => 'ro',
isa => 'Log::Dispatchouli',
default => sub {
...
},
);
has coordinates => (
is => 'ro',
isa => 'MyShip::Coord',
default => sub {
MyShip::Coord->new( 0, 0 );
},
);
has engine => (
is => 'ro',
lazy_build => 1,
);
has engine_args => (
isa => 'ArrayRef',
is => 'ro',
);
sub _build_engine {
my $self = shift;
return MyShip::Engine->new(
@{ $self->engine_args || [ fuel => 100 ] },
max_speed => 10,
coordinates => $self->coordinates,
bridge_monkey => $self->captain,
intercom => $self->intercom->proxy({ proxy_prefix => 'Engine' });
);
}
1;
can all be replaced by
package MyShip;
use Moose;
has captain => ( is => 'ro' );
has intercom => (
is => 'ro',
isa => 'Log::Dispatchouli',
default => sub {
...
},
);
has coordinates => (
is => 'ro',
isa => 'MyShip::Coord',
default => sub {
MyShip::Coord->new( 0, 0 );
},
);
with 'MooseX::Role::BuildInstanceOf' => {
target => '::Engine',
args => [ fuel => 100 ],
fixed_args => [ max_speed => 10 ],
inherited_args => [
'coordinates',
{
bridge_monkey => 'captain',
intercom => sub {
my $self = shift;
$self->intercom->proxy({ proxy_prefix => 'Engine' });
},
}
],
};
1;
Nifty, isn’t?