The standard book Perl Best Practices advises in chapter 4.5 that
one should use the Readonly
Perl module instead of the
constant
standard module for various reasons.
An example might look like this:
package Myprogram;
use Exporter;
use Readonly;
our @EXPORT = qw(conffile);
Readonly our $BASEPATH => "$ENV{HOME}/.myprogram";
sub conffile { "$BASEPATH/config.ini" }
If you want to unit test your program now, you cannot just mess around
and replace a potentially existing config file with a bogous
one. You have to create a temporary directory and use that as the base
path. That is, you have to modify your Readonly
declared variable.
I’ve not seen this documented, so I guess this might help others:
Internally the method Readonly::Scalar::STORE
is called when you do
an assignment (see man perltie
for details). In Readonly.pm
, this is
redefined to
*STORE = *UNTIE = sub {Readonly::croak $Readonly::MODIFY};
which dies with an error message. So you only have to circumvent this.
The method STORE
gets a reference of the location as first argument,
and the value as second argument. So a quick-and-dirty workaround is
just setting
*Readonly::Scalar::STORE = sub { ${$_[0]} = $_[1]; };
prior to assigning to the Readonly variable. If you want to do it properly, you should only change this locally in the block where you re-assign the value, so that subsequent attempts will again produce the usual error message. Such a test might look like this:
use strict;
use warnings;
use Test::More 'no_plan';
use Myprogram;
{
no warnings 'redefine';
local *Readonly::Scalar::STORE = sub { ${$_[0]} = $_[1]; };
$Myprogram::BASEPATH = "/tmp";
}
is(Myprogram::conffile, "/tmp/config.ini", "get config filename");
For non-scalar values, this will probably work similar. (Read the source if in doubt.)