2

I'm using Data::Dumper and Data::Dumper::Simple (DD and DDS) to print hashes in a verbose mode of a script, and I want to be able to share it with others who may not have those modules installed, so I'm checking that they're loaded.

Without checking for modules successfully loading, a MWE of how I would load and use them is:

use strict;
use warnings;

use Data::Dumper;
use Data::Dumper::Simple;
$Data::Dumper::Sortkeys = 1;

my %testHash=();

warn Dumper(\%testHash);

Which prints:

$testHash = {};

Using the method described here to first check that the modules are loaded, and only use Dumper methods if they are, I rewrote my code as:

use strict;
use warnings;


my $dumperLoaded = 1;
my $rc;

$rc = eval
{
    require Data::Dumper;
    Data::Dumper->import();
    1;
};
if(!$rc)
{
    print "Data::Dumper not found\n";
    $dumperLoaded = 0;
}

$rc = eval
{
    require Data::Dumper::Simple;
    Data::Dumper::Simple->import();
    1;
};
if(!$rc)
{
    print "Data::Dumper::Simple not found\n";
    $dumperLoaded = 0;
}
if($dumperLoaded){
    $Data::Dumper::Sortkeys = 1;
}

my %testHash=();

if($dumperLoaded){
    warn Dumper(\%testHash);
}

And my output is now:

Name "Data::Dumper::Sortkeys" used only once: possible typo at temp.pl line 51.
$VAR1 = {};

Now the hash dump does not show the variable name testHash, as if DDS did not load. However, my script did not complain that it was unable to load DDS. I can replicate this in my first MWE by commenting out use Data::Dumper::Simple;.

My question: Why is the second version of my script, with the check for module load, printing like only DD, and not DDS loaded?

Bonus question: what is the correct way to set SortKeys in a conditional module loading scenario like this?

Thanks.

SSilk
  • 2,433
  • 7
  • 29
  • 44
  • I have problems loading `Data::Dumper::Simple` via require (on Windows). So it seems that something difference. You also don't really need to test for `Data::Dumper` because it's a core module. – Sobrique Oct 24 '17 at 13:31

2 Answers2

5

Data::Dumper::Simple is a source filter. Source filters must be loaded during Perl's compile-phase, or they will not do their job on any of the source code in the script.

This might work (not tested) works:

my $dumperLoaded;
BEGIN { 
    $dumperLoaded = eval "use Data::Dumper::Simple;1" ||
                    eval "use Data::Dumper;1";
}
mob
  • 117,087
  • 18
  • 149
  • 283
  • Hmm, good thinking on the BEGIN handling. I simply couldn't see a way to get the runtime import to 'work'. – Sobrique Oct 24 '17 at 14:27
  • This works nicely, thanks! In my case, I changed the `||` in the evals to `&&` so both modules have to load in order to do data dumping. Does that makes sense? Otherwise this is great, and when both modules load successfully, the warning about `Data::Dumper::Sortkeys` only being used once goes away. – SSilk Oct 24 '17 at 16:48
1

Ok, first off - testing the return code is nice, but actually you're probably better using $@ for checking if eval worked.

E.g.:

eval { 
   require Data::Dumper;
   Data::Dumper -> import();
};
if ( $@ ) { 
   print "loading failed, error was: $@\n";
} 

But the root of your problem is this:

The only thing exported is the Dumper() function.

Well, actually that's not really true. Nothing is exported. However, a source filter is used to automatically rewrite any apparent calls to C so that it just Does The Right Thing.

Because that's what's not happening when you're loading Data::Dumper::Simple via require/import, and thus the overloading of the Dumper function isn't happening.

Looking at it - I can't actually see a simple way to call the 'alternate Dumper'

Sobrique
  • 52,974
  • 7
  • 60
  • 101