A Look at Dumping
I used Data::Dumper a lot but it leaves something to be
desired. By adding a function to MyUtils.pm, a simpler
interface can be achieved.
Last time, I created a test script for trim() in the
directory ~/perl5/lib/t/MyUtils/. The second part of this
article will create a second test script to test the function created here.
To run all the test script, use the program, prove, which is
installed with Perl.
$ prove -r ~/perl5/lib/t
This will recursively search through all the subdirectories looking for
programs ending with *.t and run them. It will produce a
summary of all the tests.
A Function with A Friendlier Interface
Data::Dumper-Dump()> allows you to put your own tags on
the values it prints, but its interface seems a little crude. Wouldn't it
be nicer if it allowed the format of tag => $value? And as
an added bonus, simpler control over its options.
So, I created vardump() with the following usage:
Usage: $text = vardump( ?%options, $tag => \$value, ... );
This first argument, ?%options is an optional reference to
a hash which contains the options for the function. I can do this since all
tags are expected to be scalars. That means they can be distinguished from
any hash reference.
The remaining arguments are in pairs. First there is a scalar containing the tag, then there is its value, which can be a scalar or a reference.
Writing the Code
The function will be added to MyUtils.pm.
Adding to
@EXPORTS_OK
First, open MyUtils.pm in your favourite editor and add
vardump to @EXPORT_OK.
our @EXPORT_OK = qw(
trim
vardump
);
Now add a brief description of what it is:
# -------------------------------------- # Name: vardump # Usage: $text = vardump( ?%options, $tag => \$value, ... ); # Purpose: A simply interface to Data::Dumper->Dump # Parameters: ?%options -- optional hash ref of options # $tag -- A variable name or other tag # $value -- A scalar or a reference # ... -- repeat tag-value pairs as needed # Returns: $text -- dumped variables #
Place the function is a block to isolate the scoping of the default options. Technically, this is called a static closure.
# create a block to limit scoping
{
use Data::Dumper;
my %default_options = (
-depth => 0, # for $Data::Dumper::Maxdepth
-indent => 1, # for $Data::Dumper::Indent
-purity => 0, # for $Data::Dumper::Purity
-sortkeys => 1, # for $Data::Dumper::Sortkeys
);
The default options are set to my preferences. You can, of course, change them to yours. See perldoc Data::Dumper for details.
Now start the function:
sub vardump {
First, check for optional options and process them. The code uses a slice to copy the given options to the hash.
# Check for optional options
my %options = %default_options;
if( ref( $_[0] ) && ref( $_[0] ) eq 'HASH' ){
my %given_options = %{ shift @_ };
# use a slice to copy
@options{ keys %given_options } = values %given_options;
}
Now, we come to the heart of the function: to create the arrays used by
Data::Dumper->Dump.
# create two arrays for Data::Dumper->Dump
my @tags = ();
my @values = ();
# process the remaining arguments
while( @_ ){
my $tag = shift @_;
my $value = shift @_;
# if value is a ref, make Dump() conform to correct type
$tag = "*$tag" if ref( $value );
# add them to the lists
push @tags, $tag;
push @values, $value;
}
Localize the Data::Dumper variables so they'll revert back
to what they were before this subroutine.
# localize Data::Dumper options
local $Data::Dumper::Indent = $options{ -indent };
local $Data::Dumper::Maxdepth = $options{ -depth };
local $Data::Dumper::Purity = $options{ -purity };
local $Data::Dumper::Sortkeys = $options{ -sortkeys };
Finally, we're ready to call Dump() and returns its
output.
return Data::Dumper->Dump( \@values, \@tags );
And finish the subroutine and scoping block.
} # end sub
} # end scoping block
Writing the Tests for the Function
Create the test script and make it executable.
$ cd ~/perl5/lib/t/MyUtils $ >01-vardump.t $ chmod a+x 01-vardump.t
Now, open the file with your favourite editor. Start with the following:
#!/usr/bin/env perl use strict; use warnings;
Set up the testing environment.
use Test::More;
BEGIN{ use_ok( 'MyUtils' ); } # test #1: check to see if module can be compiled
my $test_count = 1; # 1 for the use_ok() in BEGIN
use MyUtils qw( vardump ); # import the vardump() function
Now to add some tests.
Scalar Test
A block is used to isolate the variables.
# block for isolation of variables
{
my $var = 'test';
my $actual = vardump( scalar => $var );
my $expected = Data::Dumper->Dump( [ $var ], [ 'scalar' ] );
is( $actual, $expected, 'scalar test' );
$test_count ++;
}
Array Test
Note that the Data::Dumper variable has to be set to the
defaults of vardump.
# Array test
{
my @var = qw{ fee fie foe fue };
my $actual = vardump( array => \@var );
local $Data::Dumper::Indent = 1;
my $expected = Data::Dumper->Dump( [ \@var ], [ '*array' ] );
is( $actual, $expected, 'array test' );
$test_count ++;
}
Hash Test
Note that the Data::Dumper variable has to be set to the
defaults of vardump.
# Hash test
{
my %var = qw{ fee fie foe fue };
my $actual = vardump( hash => \%var );
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Sortkeys = 1;
my $expected = Data::Dumper->Dump( [ \%var ], [ '*hash' ] );
is( $actual, $expected, 'hash test' );
$test_count ++;
}
Depth Option Test
# Depth option test
{
my @var = ( 0, [ 1, [ 2, [ 3 ]]] );
my $actual = vardump( { -depth=>2, }, depth => \@var );
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Maxdepth = 2;
my $expected = Data::Dumper->Dump( [ \@var ], [ '*depth' ] );
is( $actual, $expected, 'depth option test' );
$test_count ++;
}
Finally...
At the end, tell Test::More how many tests were done.
# tell Test::More we're done done_testing( $test_count );
Comments
Post a Comment