In general, it is vastly simpler to have two separate modules. That said, here's an example including test cases for a module which exports three functions (alphabet, colours and numbers) where two of the functions have different behaviours in API 1 and API 2.
I've used an Exporter-type module because that's the most challenging to implement. If you're writing object-oriented code instead, then things are probably a bit easier. You can usually just create two subclasses of a base class.
use v5.14;
use strict;
use warnings;
BEGIN {
package Local::Module 2.00;
no thanks; # this is just a helper for defining multiple
# packages in the same file!
# detect requested version, and store it
my %api_preference;
sub VERSION
{
$api_preference{ scalar caller } //= $_[1] if @_==2;
shift->SUPER::VERSION( @_ );
}
use Sub::Exporter;
my $IMPORT = Sub::Exporter::build_exporter({
exports => [
alphabet => \&_build_alphabet,
numbers => \&_build_numbers,
colours => undef,
],
collectors => [qw/ defaults auto /],
});
sub import
{
push @_, auto => { api => ($api_preference{ scalar caller }//1
+.00) };
goto $IMPORT;
}
# This sub is the same for API 1 and API 2
sub colours
{
return [qw( red orange yellow green blue indigo violet )];
}
# Version 1 API returns lower-case; version 2 API is uppercase
sub _build_alphabet
{
my ($class, $name, $arg, $col) = @_;
my $api = $arg->{api} // $col->{defaults}{api} // $col->{auto}
+{api};
if ($api >= 2)
{
return sub { ['A'..'Z'] };
}
else
{
return sub { ['a'..'z'] };
}
}
# Version 1 API returns 1..5; version 2 API returns 1..10.
sub _build_numbers
{
my ($class, $name, $arg, $col) = @_;
my $api = $arg->{api} // $col->{defaults}{api} // $col->{auto}
+{api};
if ($api >= 2)
{
return sub { [1..10] };
}
else
{
return sub { [1..5] };
}
}
};
TESTING: {
use Test::More;
# Expected results:
my $alphabet1 = [ 'a'..'z' ];
my $alphabet2 = [ 'A'..'Z' ];
my $numbers1 = [ 1 .. 5 ];
my $numbers2 = [ 1 .. 10 ];
my $colours = [qw( red orange yellow green blue indigo violet )]
+;
# This consumer should get API 1
BEGIN {
package Local::Consumer1 0.001;
no thanks;
use Local::Module 1.000 -all;
};
is_deeply(
Local::Consumer1::alphabet(),
$alphabet1,
'Local::Consumer1 has alphabet() API 1',
);
is_deeply(
Local::Consumer1::numbers(),
$numbers1,
'Local::Consumer1 has numbers() API 1',
);
is_deeply(
Local::Consumer1::colours(),
$colours,
'Local::Consumer1 has colours() invariant',
);
# This consumer should get API 2
BEGIN {
package Local::Consumer2 0.001;
no thanks;
use Local::Module 2.000 -all;
};
is_deeply(
Local::Consumer2::alphabet(),
$alphabet2,
'Local::Consumer2 has alphabet() API 2',
);
is_deeply(
Local::Consumer2::numbers(),
$numbers2,
'Local::Consumer2 has numbers() API 1',
);
is_deeply(
Local::Consumer2::colours(),
$colours,
'Local::Consumer2 has colours() invariant',
);
# This consumer should get API 1
BEGIN {
package Local::Consumer3 0.001;
no thanks;
use Local::Module -all;
};
is_deeply(
Local::Consumer3::alphabet(),
$alphabet1,
'Local::Consumer3 has alphabet() API 1',
);
is_deeply(
Local::Consumer3::numbers(),
$numbers1,
'Local::Consumer3 has numbers() API 1',
);
is_deeply(
Local::Consumer3::colours(),
$colours,
'Local::Consumer3 has colours() invariant',
);
# This consumer should get API 2, except for numbers() where they
+want API 1
BEGIN {
package Local::Consumer4 0.001;
no thanks;
use Local::Module 2.000
numbers => { api => 1 },
qw( colours alphabet );
};
is_deeply(
Local::Consumer4::alphabet(),
$alphabet2,
'Local::Consumer4 has alphabet() API 2',
);
is_deeply(
Local::Consumer4::numbers(),
$numbers1,
'Local::Consumer4 has numbers() API 1',
);
is_deeply(
Local::Consumer4::colours(),
$colours,
'Local::Consumer4 has colours() invariant',
);
# This consumer wants both versions of the numbers() function
BEGIN {
package Local::Consumer5 0.001;
no thanks;
use Local::Module 2.000
numbers => { api => 1, -as => 'old_numbers' },
numbers => { api => 2 },
;
};
is_deeply(
Local::Consumer5::numbers(),
$numbers2,
'Local::Consumer5 has numbers() API 2',
);
is_deeply(
Local::Consumer5::old_numbers(),
$numbers1,
'Local::Consumer5 has old_numbers() function which is number()
+ from API 1',
);
done_testing;
};