http://qs1969.pair.com?node_id=1102131

contra-sh has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

In order to test my perl scripts, I want to override global variables (defined with the our keyword in a separated module).

Basically I have a working solution, but I don't really know if there's a better way to do that. And I need some clarifications.

To explain my issue, I reduced the code to 3 files :

- consts.pm which declare globals variables and set their content.

- logging.pm which will use consts.pm and use the global vars

- run-unit-tests.pl which overrides the content of these variables

My current solution is like this :

consts.pm
use Exporter; our @ISA = 'Exporter'; our @EXPORT = qw($VAR1 $VAR2); our $VAR1="var1"; our $VAR2="var2"; 1;
logging.pm
use consts; our ($VAR1, $VAR2); print "Import...\n"; print "VAR1 : [$VAR1]\n"; print "VAR2 : [$VAR2]\n"; sub logging_func() { print "Running function...\n"; print "VAR1 : [$VAR1]\n"; print "VAR2 : [$VAR2]\n"; } 1;
run-unit-tests.pl
use consts; our ($VAR1, $VAR2); local $VAR1 = "override1"; local $VAR2 = "override2"; use logging; logging_func();

The produced output is like this :

Import... VAR1 : [var1] VAR2 : [var2] Running function... VAR1 : [override1] VAR2 : [override2]

Note that I use "local" because seems like this is the good option to override global vars (I'm reading the camel book). Seems like the override only works when I call the function. That's weird because I modified the value before including the logging module.

Other topic, could you please tell me when and why I should use (or not use) the Exporter core module. Because removing it seems to have no impact at all...

Next 3 code snippets produce the same output without teh use of Exporter code module.

consts.pm
our $VAR1="var1"; our $VAR2="var2"; 1;
logging.pm
use consts; our ($VAR1, $VAR2); print "Import...\n"; print "VAR1 : [$VAR1]\n"; print "VAR2 : [$VAR2]\n"; sub logging_func() { print "Running function...\n"; print "VAR1 : [$VAR1]\n"; print "VAR2 : [$VAR2]\n"; } 1;
use consts; our ($VAR1, $VAR2); #print "VAR1 : [$VAR1]\n"; #print "VAR2 : [$VAR2]\n"; local $VAR1 = "override1"; local $VAR2 = "override2"; use logging; logging_func();

When I run perl run-unit-tests.pl I get this output:

Import... VAR1 : [var1] VAR2 : [var2] Running function... VAR1 : [override1] VAR2 : [override2]

I thought that using a package name was a possible solution but it isn't... As you can see on the next code snippets :

consts.pm
use Exporter; package consts; our $VAR1="var1"; our $VAR2="var2"; 1;
logging.pm
use consts; print "Import...\n"; print "VAR1 : [$consts::VAR1]\n"; print "VAR2 : [$consts::VAR2]\n"; sub logging_func() { print "Running function...\n"; print "VAR1 : [$consts::VAR1]\n"; print "VAR2 : [$consts::VAR2]\n"; } 1;
run-unit-tests.pl
use consts; $consts::VAR1 = "override1"; $consts::VAR2 = "override2"; # OR #local $consts::VAR1 = "override1"; #local $consts::VAR2 = "override2"; use logging; logging_func();

This produce the same output :

Import... VAR1 : [var1] VAR2 : [var2] Running function... VAR1 : [override1] VAR2 : [override2]

Note that using "local" keyword during overriding step does not change anything.

If I use $main without specifying the package name, I have the exact same behavior (not a surprise of course).

So to summarize :

- Is it a better solution than mines ?

- Could you please explain this behavior ?

- Should I see any difference if I use require instead of use?

- Why do I have no impact when I stop using Exporter module ? I can't remember why I needed Exporter (maybe because I have "use strict" and "use warnings" in the original scripts...)

I don't really want to use non core modules (I read about PadWalker somewhere). At the moment, I don't really want to use packages if possible (nothing against it, but if there's a solution with packages, there's probably another one without packages).

Thank you a lot by advance.

And... I'm pretty new to perl, and I would say... perl rocks!

Regards.

Thibault