Reputation: 311
I have an API A::B that's "use"d by others in their scripts like so:
use A::B;
my $out = A::B->new(dir => $dir);
...
Now, I want a different version of A::B to be used depending on some parameter of the attribute $dir passed to the constructor. The user of this module has no need to know this - all he has to do is
use A::B
in his code, and expect that the module is picked up from the right location. Is it possible to do this?
Upvotes: 0
Views: 60
Reputation: 386461
Messy:
BEGIN {
my $version = '2.0';
require "/home/$version/lib/A/B.pm";
}
my $obj = A::B->new();
If it's an external entity controlling the choice, then simply adjust Perl's library search path.
version=2.0
PERL5LIB="/home/$version/lib" script
use A::B qw( );
my $obj = A::B->new();
If it's an internal choice, use submodules instead.
package A::B;
sub new {
my ($class, $version) = @_;
$version =~ s/\./_/g;
$class .= "::V$version";
require $class;
return $class->new(@_);
}
1;
use A::B qw( );
my $version = '2.0';
my $obj = A::B->new($version);
Upvotes: 3
Reputation: 40778
If you allow a different package name of the other version internally (while the user still uses A::B
and does not know about the different names of the same module), you could achieve this. For example, let's say the different version of the module is internally called A::B::C
. Then package A::B
could be like this:
package A::B;
sub new {
my ( $class, %opts ) = @_;
if ( $opts{dir} eq "dir1" ) {
require A::B::C;
return A::B::C->new();
}
else {
my $self = {};
return bless $self, $class;
}
}
1;
Upvotes: 0
Reputation: 1431
You can't have different versions of a module with the same name.
What I would do instead is having different subclasses of A::B
, and a Factory class that instantiates objects of the appropriate class, choosing and loading it based on the factory invocation parameters.
For example:
my $out = A::B::Factory->create( dir => $dir );
# $out is a A::B::Foo or A::B::Bar depending on $dir
In the factory class:
package A::B::Factory;
use UNIVERSAL::require;
sub create {
my (undef, %params) = @_;
my $dir = $params{ dir };
# some strategy to decide which class has to be used.
# $class will be a string like "A::B::Foo" or "A::B::Bar"
# or in general the same of an existing class in your system.
my $class = ...;
$class->use;
return $class->new();
}
Upvotes: 1