Reputation: 347
I use a Perl Moose Role (Import::Git::Role
) as an Abstract Base Class to share common behaviour between a Class an actual implementation of functionality (Import::Git
) and a Class that performs some logging instead (Import::Git::dryrun
).
I would like the dryrun class to be transparent. I want to create a object like this:
my $git = Import::Git->new( dryrun => $dryrun );
The variable dryrun could be 0 or 1. If it is 1, I would like to construct an Import::Git::dryrun
object instead, basically replacing the Import::Git
object with it. Thats intended because they share all methods via the role.
I have tried to exchange the Object during the BUILDARGS Method like this:
around BUILDARGS => sub {
my $orig = shift;
my $class = shift;
my %args = ( @_ == 1 ? %{ $_[ 0 ] } : @_ );
if ( !%args || $args{ 'dryrun' } != 1 ) {
return $class->$orig( @_ );
}
else {
return Import::Git::dryrun->$orig( @_ );
}
};
but this doesn't achieve what I am trying to do, it constructs the old class:
DB<1> x Import::Git->new( dryrun => 1 )
0 Import::Git=HASH(0x2fd9210)
'dryrun' => 1
DB<2> x Import::Git->new()
0 Import::Git=HASH(0x301dbb8)
'dryrun' => 0
DB<3>
I thought I would probably have to call the new Method of the dryrun-method so I made the following exchange:
# change this:
return Import::Git::dryrun->$orig( @_ );
# to this
return Import::Git::dryrun->new( @_ );
But it returns BUILDARGS did not return a HASH reference
.
What am I missing?
Upvotes: 2
Views: 362
Reputation: 385897
Having a constructor build a different class than the one requested is icky. I wouldn't take the approach you did even if it did work. I would use
sub factory {
my ($class, %opts) = @_;
return $opt{dryrun} ? $class.'::dryrun' : $class;
}
Import::Git->factory( dryrun => $dryrun )->new( ... )
or
sub instantiate {
my ($class, %opts) = @_;
return ( delete($opt{dryrun}) ? $class.'::dryrun' : $class )->new(%opts);
}
Import::Git->instantiate( dryrun => $dryrun, ... )
Upvotes: 4
Reputation: 4013
BUILDARGS
is used to manipulate the argument list you pass to the objects constructor before the object is created so will have no impact on what new returns. Instead of around BUILDARGS
you might want to try around new
, then you can replace the object returned by new with your dry run object.
Upvotes: 2