contra-sh has asked for the wisdom of the Perl Monks concerning the following question:
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.pmlogging.pmuse Exporter; our @ISA = 'Exporter'; our @EXPORT = qw($VAR1 $VAR2); our $VAR1="var1"; our $VAR2="var2"; 1;
run-unit-tests.pluse 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); 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.pmlogging.pmour $VAR1="var1"; our $VAR2="var2"; 1;
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.pmlogging.pmuse Exporter; package consts; our $VAR1="var1"; our $VAR2="var2"; 1;
run-unit-tests.pluse 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;
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