Home > Mobile >  Perl: Assign a value to a variable only when it is to be used
Perl: Assign a value to a variable only when it is to be used

Time:08-24

This is in perl Windows.

Code Snippet:

    my $TestVarDirName;
    my $testScript = "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $TestVarDirName -t lnx64"; 
    &runAndMonitor(\@ForRun, "$MSROO/logs/Test.log");

    $testScript = "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/hash -m win -serial 32 $TestVarDirName -t wint";    ### Added 
    &runAndMonitor(\@ForRun2, "$MSROO/logs/Test2.log"); ### Added

     sub runAndMonitor {
        my @ForRunPerProduct =  @{$_[0]};
        my $logFile = $_[1];
            foreach my $TestVar (@ForRunPerProduct) {
                print "$testScript is the testScript command\n";  ### Line 9
                $TestVarDirName = $TestVar;
                $TestVarDirName = dirname ($TestVarDirName);
                my $filehandle;       
               if ( !($pid = open( $filehandle, "-|" , " $bashexe -c \"cd $smokesBasePath \; $testScript \" >> $logFile ""))) {                
                    die( "Failed to start process: $!" );
                }
           }
     }

I want that in piped open command, $testScript variable substitutes the value of $TestVarDirName only when $testScript is called (dynamically), and not in the start of the script.

Currently, at "line 9" (as mentioned in code snippet), I am getting U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash -t lnx64 is the testScript command. Of course because initially at the start of script, $TestVarDirName has no value in it, and command would work according to its initial value. How can I avoid it, and let the latest value of $TestVarDirName be used?

CodePudding user response:

Use an anonymous sub to build the string:

my $testScriptBuilder = sub { "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $_[0] -t lnx64" }; 
...
foreach my $TestVar (@ForRunPerProduct) {
    local $TestVarDirName = dirname($TestVar);
    my $testScript = $testScriptBuilder->($TestVarDirName);
    ....
}

If you think that having $_[0] instead of $TestVarDirName in the string makes things less clear, then you could use this sub instead:

my $testScriptBuilder = sub { 
    my $TestVarDirName = $_[0];
    return "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $TestVarDirName -t lnx64" 
}; 

The interpolation of $_[0] (or $TestVarDirName) in "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $_[0] -t lnx64" is only done when the subroutine testScriptBuilder is evaluated, which is when you actually call it with testScriptBuilder->($TestVarDirName). Thus, $TestVarDirName will have the expected value (dirname($TestVar)).


Alternatively, you could use the Template module:

my $testScriptTemplate = "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash [% TestVarDirName %] -t lnx64";
...
foreach my $TestVar (@ForRunPerProduct) {
  my $TestVarDirName = dirname($TestVar);
  Template->new->process(\$testScriptTemplate, { TestVarDirName => $TestVarDirName }, \my $testScript);
  ...
}

The downside is that you have to modify the initial string in a more intrusive manner (replacing $TestVarDirName by [% TestVarDirName %]). However, this is also an upside, as it allows you to specify what should be interpolated early and what shouldn't: all of the variables in the template string will be interpolated right away, while the things inside [% %] will be interpolated later.

CodePudding user response:

Dada's answer is the sane way of doing this, but if you'd like a less sane way...

use String::Interpolate::Delayed;

my $TestVarDirName;
my $testScript = delayed "U:/perl.exe U:/devAuto.pl -p SHELL=/usr/bin/bash $TestVarDirName -t lnx64"; 
&runAndMonitor(\@ForRun, "$MSROO/logs/Test.log");

sub runAndMonitor {
    my @ForRunPerProduct =  @{$_[0]};
    my $logFile = $_[1];
        foreach my $TestVar (@ForRunPerProduct) {
            print "$testScript is the testScript command\n";  ### Line 9
            $TestVarDirName = $TestVar;
            $TestVarDirName = dirname ($TestVarDirName);
            my $filehandle;       
           if ( !($pid = open( $filehandle, "-|" , " $bashexe -c \"cd $smokesBasePath \; $testScript \" >> $logFile ""))) {                
                die( "Failed to start process: $!" );
            }
       }
}

CodePudding user response:

I think there's a much simpler way to go here. Set up a template for the string you want, then fill in the placeholders when you are ready to use it. No fancy subroutine tricks or modules:

 my $testScript_template = "U:/perl.exe ... %s -t lnx64"; 

 sub runAndMonitor {
    ...
    foreach my $TestVar (@ForRunPerProduct) {
        ...
        $TestVarDirName = dirname ($TestVarDirName);
        $testScript = sprintf $testScript_template, $TestVarDirName;
        ...
   }
 }

But I might move that template into the smallest scope it needs:

 sub runAndMonitor {
    ...
    foreach my $TestVar (@ForRunPerProduct) {
        state $testScript_template = "U:/perl.exe ... %s -t lnx64"; 
        ...
        $TestVarDirName = dirname ($TestVarDirName);
        $testScript = sprintf $testScript_template, $TestVarDirName;
        ...
   }
 }
  • Related