Perl Best Practices
17.4. Version Requirements
Enforce your version requirements programmatically. Telling future maintainers about a module's version requirements is certainly a good practice: package Payload; # Only works under 5.6.1 and later use IO::Prompt; # must be 0.2.0 or better, but not 0.3.1 use List::Util qw( max ); # must be 1.13 or better use Benchmark qw( cmpthese ); # but no later than version 1.52 # etc.
But telling Perl itself about these constraints is an even better practice, as the compiler can then enforce those requirements. Perl has a built-in mechanism to do (some of ) that enforcement for you. If you call use with a decimal number instead of a module name, the compiler will throw an exception if Perl's own version number is less than you specified: package Payload; use 5.006001; # Only works under 5.6.1 and later
Unfortunately, that version number has to be an old-style decimal version. You can't use the version module's qv( ) subroutine (as recommended in the previous guideline), because the compiler interprets the qv identifier as the name of a module to be loaded: package Payload; use version; use qv('5.6.1'); # Tries to load qv.pm If you load a module with a normal use, but place a decimal version number after its name and before any argument list, then the compiler calls the module's VERSION method, which defaults to throwing an exception if the module's $VERSION variable is less than the version number that was specified: use IO::Prompt 0.002; # must be 0.2.0 or better use List::Util 1.13 qw( max ); # must be 1.13 or better
Note that there are no commas on either side of the version number; that's how the compiler knows it's a version restriction, rather than just another argument to the module's import( ) subroutine. Once again, the version number has to be an old-style decimal version. A qv( ) isn't recognized: use IO::Prompt qv('0.2.0') qw( prompt ); # Syntax error
Perl doesn't provide a built-in way to specify "no later version than..." or "any version except...", apart from testing those conditions explicitly: package Payload; use version; use Carp; use IO::Prompt qw( prompt ); use Benchmark qw( cmpthese ); # Version compatibility... BEGIN { # Test against compiler version in $] # (there's no nice use English name for it) croak 'Payload only works under 5.6.1 and later, but not 5.8.0' if $] < qv('5.6.1') || $] == qv('5.8.0'); croak 'IO::Prompt must be 0.2.0 or better, but not 0.3.1 to 0.3.3' if $IO::Prompt::VERSION < qv('0.2.0') || $IO::Prompt::VERSION >= qv('0.3.1') && $IO::Prompt::VERSION <= qv('0.3.3'); croak 'Benchmark must be no later than version 1.52' if $Benchmark::VERSION > qv('1.52') ; } This approach is tedious, repetitive, and error-prone, so naturally there's a module on the CPAN to simplify the process of loading a module and verifying that its version number is acceptable. The module is named only and it can be used (under Perl 5.6.1 and later) like so: package Payload; # Works only under Perl 5.6.1 and later, but not 5.8.0 use only q{ 5.6.1- !5.8.0 }; # IO::Prompt must be 0.2.0 or better, but not 0.3.1 to 0.3.3 use only 'IO::Prompt' => q{ 0.2- !0.3.1-0.3.3 }, qw( prompt ); # Benchmark must be no later than version 1.52 use only Benchmark => q{ -1.52 }, qw( cmpthese );
That is, you write use only, followed by the module name, followed by a single string that specifies the range of versions that are acceptable. The use only first loads the module you requested, then checks whether the version it loaded matches the range of versions you specified. You can specify ranges of acceptable versions ('1.2.1-1.2.8'), or a minimum acceptable version ('2.7.3-'), or a maximum acceptable version ('-1.9.17'). You can negate any of these, to specify unacceptable versions ('!1.2.7', '!3.2-3.2.9'). Most importantly, you can combine these different types of specification to provide "ranges with holes". For example, in the previous example: use only 'IO::Prompt' => '0.2- !0.3.1-0.3.3', qw( prompt );
this means "any version at or above 0.2, except those in the range 0.3.1 to 0.3.3". The only module has other, even more powerful features. It provides exceptional support for legacy applications that may rely on outdated versions of particular modules. You can install multiple versions of the same module, and then use only will select the most appropriate available version of the module for each program. |