NAME
Data::Dumper::EasyOO - wraps DD for easy use of printing styles
SYNOPSIS
{
# set common style for all objects created
use Data::Dumper::EasyOO (indent => 1);
# build an EzDD object, adding print-styles
my $ezdd = Data::Dumper::EasyOO->new (terse => 1);
# use the same ezdd obj repeatedly
print "default: ", $ezdd->($_) for @userdata;
# label it $foo, not $VAR1
print $ezdd->(foo => $_) for @userdata;
# alter printing style using DD API
$ezdd->Terse(0);
print "default: ", $ezdd->($_) for @userdata;
# alter many print styles at once
$ezdd->Set (terse=>0, sortkeys=>1);
print "default: ", $ezdd->($_) for @userdata;
# set autoprint to STDOUT
$ezdd->Set (autoprint => 1);
$ezdd->( you_used_pkgs => \%INC);
# set autoprint to an opened filehandle
$ezdd->Set (autoprint => $fh);
$ezdd->( you_used_pkgs => \%INC);
}
DESCRIPTION
This package wraps Data::Dumper, and gives an object thats as easy to print with as Dumper(), DDs exported procedural interface. Its also easy to control print-style, as theyre set within the EzDD object.
In this document, I use DD as shorthand for Data::Dumper, DD-OO for its object oriented API, and EzDD for this class. Despite the package name, I assume some knowledge about DD, at least wrt explaining why EzDD is better.
In DD-OO, you must provide new() with the data to print, then change print-style, then print. This 3 step usage tends to be verbose. Because theres no (currently documented) way to un-bind the data, most users just toss the DD object.
In contrast, EzDD is geared for object reuse, just think of it like a printer; print-style is analogous to color, paper-size, etc. You just build an object for each different print style you want, and use them repeatedly. A single EzDD object is enough for most users.
FEATURE COMPARISON
In the following, I compare EzDD to either or both DD and DD-OO. This section is meant to be somewhat cursory; the next section delves a bit deeper.
construct the EzDD object
To use EzDD, you have to (blow a line of code to) create an EzDD object, but you can initialize it once and for all, with less typing than with DDs package vars.
new: $ezdd = Data::Dumper::EasyOO->new(indent=>1,sortkeys=>1);
old: {
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
}
EzDD printing is brief
Once your $ezdd object is built, printing is as easy as using Dumper(). Note that $ezdd doesnt even need a method name !
new: print $ezdd->($foo);
dd: print Dumper ($foo);
dd_oo: print Data::Dumper->Dump($foo);
Using autoprint mode, you can drop the 'print'
$ezdd->Set(autoprint=>1);
$ezdd->($foo);
Easier Labelling of Data
old: print Data::Dumper->Dump ( [$a,$b,$c], [qw(a b c)] );
new: print $ezdd -> ( a=>$a, b=>$b, c=>$c )
Labelling data wih DD-OO is counterintuitive; most perl users like and expect to see labelled => $data
. DD-OO is also too punctuation intensive, too dependent on having exactly 2 arrayref args, and having them the same length. Also, note that Dumper() cannot label data at all.
You can independently control print-style on each object
With Dumper(), print-style is controlled either globally, or by localizing a set of variables. With EzDD, print-style can be set on the object. This is a big advantage when you want 2 styles simultaneously.
DD: {
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Sortkeys = 1;
print Dumper (\@foo);
}
new: {
$ezdd->Set(indent=>1,sortkeys=>1); # do once on obj
print $ezdd->(\@foo);
}
The next example shows DD_OO style control. Its tedious if you have to do it each time you want to print.
You can print repeatedly with same object
In DD-OO, you must provide the data to be dumped when the object is created, only then can the print-style be changed. This means lots of extra typing and method calls, thus discouraging use of OO style.
EzDD: {
$d->Set(indent=>1,deepcopy=>1);
print $d->($_) foreach @data;
}
DD_OO:
foreach $datum (@data) {
$d = Data::Dumper->new($datum);
$d->Sortkeys(1)->Indent(1)->Deepcopy(1);
print $d->Dump;
}
FEATURES
Controlling Print Style for objects
With EzDD, you control print style of single objects, either by speifying at creation, or altering thereafter.
$ezdd = Data::Dumper::EasyOO->new(%printOptions);
$ezdd->Set(%newprintOptions); # update many
$ezdd->Indent(1); # update by DDs methods
$ezdd->Terse(1)->Sortkeys(1); # update in chains (like DD)
These settings stay with the object thru its lifetime, and are independent of other objects settings. If you dont set preferences as above, DDs globals are used by default.
Controlling Print Style via use
Print style can also be set at use-time, these are defaults for every object built thereafter. They can be overridden for individual objects, by any of new(), Set(), or DDs style-setting methods.
The styles are saved separately for each package using EzDD, so Foo.pm and Bar.pm can have a different styles.
Easy Labelling for your Data
print $ezdd->(@args);
@args are treated as pairs of labelled data if possible; ie if arglist is even length, and if the 'labels' are scalars. If you have an array (of scalars) that is incorrectly printed as labelled data, you can force things by passing its ref; ie $ezdd->([0..3]) vs $ezdd->((0..3)).
This maybe a bit aggressive for your tastes, but I dont use DD with simple scalars (except by accident ;-) and my habit with Dumper() is to always pass a single data-arg anyway, ex \@foo. YMMV. FWIW - DD::Dumper() also does this; it calls Data::Dumper->Dump([@_]). For more specifics, check t/labels.t or the code.
Auto-Printing
Autoprinting allows you to drop the 'print':
use Data::Dumper::EasyOO ( autoprint => 1 );
my $ez = Data::Dumper::EasyOO->new();
$ez->('the-includes' => \%INC);
The autoprint property can be 1 for STDOUT, 2 for STDERR, or an open FileHandle, and will write accordingly. You can also change this afterwards (note the tag change);
my $ez2 = EzDD->new(_ezdd_autoprint => 2); # set in ctor
$ez->Set(_ezdd_autoprint => 2); # change during use
Speed
Dumper() builds a new DD object for each print, and this has non-zero runtime costs. Ive included a benchmark in the testsuite which shows 3% to 24% improvement on a linux 686 laptop, using the small data chunks I used for testing. With large data sets, printing time dominates, and the improvement drops asymtotically to 0%.
INTERFACE
As I hope is clear by now, $ezdd->($data) renders the data.
new(%printOptions) creates a new EzDD object, and calls Set() to establish desired printing behavior of that instance.
Set(%printOptions) alters the print style of an existing EzDD object. It accepts option names matching the methods that DD provides, and lowercase versions of them. %option values are not validated by EzDD, DD itself may do so, but I havent tested this, and make no promises.
Set() also does not provide accessor functionality; most DD methods return the DD object in support of method chaining, they cannot return the attribute values.
AUTOLOAD() allows you to invoke the familiar DD methods on an EzDD object, its a convenience method which calls Set().
pp() and dump() are methods to "pretty-print". The names were borrowed from Data::Dump
IMPLEMENTATION
The class builds a blessed CODEref object, for which perl also allows method-lookups. This hybrid nature is key to the viability of the design.
new() builds a private Data::Dumper object, then builds and returns a closure on that object. The closure provides the printing interface directly, and also provides (via special data value - slightly hackish) access to the underlying DD object for the other methods; Set() and AUTOLOAD().
BUGS
EasyOO relys on Data::Dumper, so if youre using 5.00503 and havent upgraded DD, some print-style controls wont be available.
Validation of DD methods is based on checks of $DD::VERSION, and may have a few errors, or may miss a few DD versions in between original and current.
Some allowed methods may be nonsense in this context; I havent used them all myself in real-life, or in tests.
Theres no accessor functionality for print-styles.
Possible Applications
A client-class dumper. You can create one or a few EzDD objects in your Foo.pm module, and tailor them to serialize Foo objects however you like. With Sortkeys, you can serialize only the object keys you want, for persistent storage, or for debugging purposes. Maxdepth, Varname, etc are all similarly usable.
CAVEATS, Enhancements, TBD, TBC
- method-less invocation may be over-cool.
-
This was an experiment (in blessed coderefs) that went well enough to continue. If this feature makes you itch, you can use $ezdd->pp() $ezdd->dump() instead.
- Brand new code, with the usual caveats.
-
Tested OK against 5.005_03, 5.8.2, and many in between, both threaded and unthreaded. As wise men say, 'release early, release often'
- Too much dependency on DD
-
The down-side of 5.00503 compatibility is that DD was less capable back then. Barbie caught and reported some test failures on ActiveState 5.6.1 due to then non-existent DD methods used in some aggressive tests. Ive detuned t/chains.t, but others may lurk.
- No validation on %printOptions values.
-
Arrayrefs & hashrefs are passed verbatim to DD object. If DD expects a particular value type, you must provide it; I do no checking, and rely on DD to complain as fitting.
If DD carps about stuff passed in, it may blame EzDD. I regard this as a user error, youve been warned. I will accept patches which place blame properly ;-)
- format control not per-use, but on object only
-
You cant localize print options for 1 usage. This is because those DD pkg vars, localized or not, are copied into the object when its constructed, and are thereafter ignored by that object. This *could* be fixed by changes to DD, but I dont see the value, Id anticipate a slowdown, and I dont expect DDs maintainer would accept that.
- auto-labelling may be overzealous.
-
In particular, $ezdd->(1,2,3,4) will treat 1,3 as labels. At minimum it needs more tests.
- Reporting of illegal methods can change capitalization
-
DD has nice property that object attributes are lower-cased versions of the method names. I leverage this, and use lc(), ucfirst() to allow mixed case print-styles, but this may result in slightly confusing capitalization differences.
- not *entirely* data-agnostic
-
$ezdd->('__SA__')
will return underlying DD object, unlike all other data. This hackery is needed cuz the closure is the only handle to the DD object, unless Ive missed something. - add no_reset option
-
EzDD uses $ddo->Reset so that $ddo can be reused. a no_reset option would allow you to defeat that. The internal flag 'ddez_noreset' already exists, but the details are subject to change.
To Be Considered
- AUTOLOAD() accessor mode
-
This conflicts with support for method-chaining (ie returning the object so it can be chained). Since DD supports it, we should too.
It may be possible by defining sub _get($prop), calling it from AUTOLOAD if not @args. This would break chaining for accessors, but thats 'broken by design' anyway.
- Sortkeys as hashref
-
If sortkeys was a hashref (with arrayref values), the keys *could* specify applicability of the arrayref based upon the data being dumped; its type, depth, tag, etc.. See "Possible Applications".
Reasons not to bother: The key would need som XPath-ish form, which may be sufficient reason to kill the idea at birth. It would also need DD support, at very least a callback scheme.
Comments welcome.
Whats overkill ?
SEE ALSO
Data::Dumper is used internally (you know by now ;-). If you really want to, you can reuse DD objects without this module. See the code for how to do so.
Data::Dump also has a simple interface, ie a single function, imported as dump() or pp(). It doesnt have print-style controls, and doesnt have DDs evaluable output, so its not directly usable in place of DD, where this is. On the other hand, its output is magically data-dependent; if the data fits on a single line, it gets printed that way.
ACKNOWLEDGMENTS
Gurusamy Sarathy for writing DD, I love it and use it *ALL* the time, its often my microscope of choice. I cant leave the above critique as the only commentary.
AUTHOR
Jim Cromie <jcromie@cpan.org>
Copyright (c) 2003 Jim Cromie. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
I dont suppose I'll ever recover the (modest) development time via reduced keystrokes, but CPAN has saved me so much already; heres a little give-back. And besides, perl is fun, like an always-new toy.