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