Version-specific fallback code

I have a script that needs to run on multiple servers, however, each server may not have the same Perl version as the other functions.

Perl v5.14 introduced the / r modifier for regular expressions , which returns the substitution result and leaves the original text alone. If this is not available, I would like to use some fallback code.

Here's an example:

#!/usr/bin/perl

# Don't use cryptic variable names
use English;

my $str = "Hello, World!";
my $search = ',';

if ($PERL_VERSION ge v5.14) {
    print "Using version that supports /r modifier\n";

    # Perl v5.14 introduced the /r flag for regular expressions
    # From the perldoc: r  - perform non-destructive substitution and return the new value
    print "After replacement: " . ($str =~ s/\Q${search}\E/_/gr) . $/;
    print "Original string: " . $str . $/;

} else {
    print "This version does not support the /r modifier\n";

    # Prior to Perl v5.14, no /r option existed and the original string will be clobbered
    # To deal with this, we need to make a copy first, then modify the copy instead
    my $str_copy = $str;
    $str_copy =~ s/\Q${search}\E/_/g;

    print "After replacement: " . $str_copy . $/;
    print "Original string: " . $str . $/;
}

      

When Perl v5.14 is available, running the script gives me the results I want:

$ ./version_dependent.pl
Using version that supports /r modifier
After replacement: Hello_ World!
Original string: Hello, World!

      

When using a version lower than v5.14, I get a syntax error due to r

:

$ ./version_dependent.pl
Bareword found where operator expected at ./version_dependent.pl line 15, near "s/\Q${search}\E/_/gr"
syntax error at ./version_dependent.pl line 15, near "s/\Q${search}\E/_/gr"
Execution of ./version_dependent.pl aborted due to compilation errors.

      

I would like to receive:

$ ./version_dependent.pl
This version does not support the /r modifier
After replacement: Hello_ World!
Original string: Hello, World!

      

Is there a way to make the script behave as intended?

If it were a C-like language, I handle the problem with a preprocessor, but I don't think Perl has this functionality.


Edit : The above code is just an example.
There are functions in the actual application that I use from 5.14 for performance reasons. I can manually update functionality in versions below 5.14, but performance suffers.

+3


source to share


2 answers


Many of the latest features are not cutting edge. As you saw, you will get compile time errors with a function that is too new for the version of Perl you are using. Using block- eval

will not help because the contents of the block must be valid for the current perl interpreter.

You are on the right track checking your current perl version and branching. $]

variable
is one way to do it. The check $Config{PERL_VERSION}

(after you use Config

) is different.

ThisSuitIsBlack does not indicate a pragma if

, namely

use if $] >= 5.014, 'Foo::New';  # take advantage of latest syntax,features
use if $] <= 5.014, 'Foo::Old';  # workarounds for missing features 

      

to load various modules depending on the capabilities of your current perl. At run time, conditional statements require

can work the same way.



if ($] >= 5.014) {
    require Foo::New;
} else {
    require Foo::Old;
}

      

Finally, the eval block is not a viable method for version-dependent code, but the eval. The bottom line is as follows:

BEGIN {  # BEGIN block so these subs get parsed at compile time
    if ($] >= 5.014) {
        eval q^*substwrepl = sub {
            my ($str,$search) = @_;
            $str =~ s/\Q${search}\E/_/gr
        };^;
    } else {
        eval q^*substwrepl = sub {
            my ($str,$search) = @_;
            my $str_copy = $str;
            $str_copy =~ s/\Q${search}\E/_/g;
            $str_copy;
        };^;
    }
}

...  # later in your program
my $str = "Hello, world";
print "After replacement: ", substrwrepl($str, ","), "\n";
print "Original string: ", $str, "\n";

      

See moduleTest::Builder

for real use of this construct.

+3


source


Wrap it as a string eval

(because the block form eval

will lead to the same error):



#!/usr/bin/perl

# Don't use cryptic variable names
use English;

my $str = "Hello, World!";
my $search = ',';

if ($PERL_VERSION ge v5.14) {
    print "Using version that supports /r modifier\n";

    # Perl v5.14 introduced the /r flag for regular expressions
    # From the perldoc: r  - perform non-destructive substitution and return the new value
    eval 'print "After replacement: " . ($str =~ s/\Q${search}\E/_/gr) . $/;';
    print "Original string: " . $str . $/;

} else {
    print "This version does not support the /r modifier\n";

    # Prior to Perl v5.14, no /r option existed and the original string will be clobbered
    # To deal with this, we need to make a copy first, then modify the copy instead
    my $str_copy = $str;
    $str_copy =~ s/\Q${search}\E/_/g;

    print "After replacement: " . $str_copy . $/;
    print "Original string: " . $str . $/;
}

      

+1


source







All Articles