File Coverage

blib/lib/Data/Dumper/EasyOO.pm
Criterion Covered Total %
statement 131 135 97.0
branch 47 54 87.0
condition 12 14 85.7
subroutine 18 18 100.0
pod 3 3 100.0
total 211 224 94.2


line stmt bran cond sub pod time code
1             #!perl
2              
3             package Data::Dumper::EasyOO;
4 26     26   414335 use Data::Dumper();
  26         186623  
  26         978  
5 26     26   226 use Carp 'carp';
  26         616  
  26         1747  
6 26     26   179 use strict;
  26         51  
  26         1007  
7              
8 26     26   949 use 5.005_03;
  26         97  
  26         1095  
9 26     26   139 use vars qw($VERSION);
  26         50  
  26         7046  
10             $VERSION = '0.0503';
11              
12             =head1 NAME
13              
14             Data::Dumper::EasyOO - wraps DD for easy use of various printing styles
15              
16             =head1 ABSTRACT
17              
18             EzDD is an object wrapper around Data::Dumper (henceforth just DD),
19             and uses an inner DD object to produce all its output. Its purpose is
20             to make DD's OO capabilities easier to use, ie to make it easy to:
21              
22             1. label your data meaningfully, not just as $VARx
23             2. make and reuse EzDD objects
24             3. customize print styles on any/all of them independently
25             4. provide essentially all of DD's functionality
26             5. do so with fewest keystrokes possible
27              
28             =head1 SYNOPSIS
29              
30             1st, an equivalent to DD's Dumper, which prints exactly like Dumper does
31              
32             use Data::Dumper::EasyOO;
33             print ezdump([1,3]);
34              
35             which prints:
36              
37             $VAR1 = [
38             1,
39             3
40             ];
41              
42             Here, we provide our own (meaningful) label, and use autoprinting, and
43             thereby drop the 'print' from all ezdump calls.
44              
45              
46             use Data::Dumper::EasyOO (autoprint => 1);
47             my $gl = { Joe => 'beer', Betsy => 'wine' });
48             ezdump ( guest_list => $gl);
49              
50             which prints:
51              
52             $guest_list = {
53             'Joe' => 'beer',
54             'Betsy' => 'wine'
55             };
56              
57              
58             And theres much more...
59              
60             =head1 DESCRIPTION
61              
62             EzDD wraps Data::Dumper, and uses an inner DD object to print/dump.
63             By default the output is identical to DD. That said, EzDD gives you a
64             nicer interface, thus encouraging you to tailor DD output the way you
65             like it.
66              
67             A primary design feature of EzDD is that you can choose your preferred
68             printing style in the 'use' statement. EzDD replaces the usual
69             'import' semantics with the same (property => value) pairs as are
70             available in new().
71              
72             You can think of the use statement as a way to set new()'s default
73             behavior once, and reuse those styles (or override and supplement
74             them) on EzDD objects you create thereafter.
75              
76             All of DD's style-setting methods are available in EzDD as both
77             properties to new(), and as object methods; its your choice.
78              
79             =head2 An easy use of ezdump()
80              
81             For maximum laziness support, ezdump() is exported into your
82             namespace, and supports the synopsis example. $ezdump is also
83             exported; it is the EzDD object that ezdump() uses to do its dumping,
84             and allows you to tailor ezdump()s print-style. It also lets you use
85             OO style if you prefer.
86              
87             Continuing from 2nd synopsis example...
88              
89             $ezdump->Set(sortkeys=>1);
90             ezdump ( guest_list => $gl );
91             print "\n";
92             $ezdump->Indent(1);
93             ezdump ( guest_list => $gl );
94              
95             which prints:
96              
97             $guest_list = {
98             'Betsy' => 'wine',
99             'Joe' => 'beer'
100             };
101              
102             $guest_list = {
103             'Betsy' => 'wine',
104             'Joe' => 'beer'
105             };
106              
107             The print-styles are set 2 times; 1st as a property setting, 2nd done
108             like a DD method. The styles accumulate and persist on the object.
109              
110              
111             =cut
112              
113             ;
114             ##############
115             # this (private) reference is passed to the closure to recover
116             # the underlying Data::Dumper object
117             my $magic = [];
118             my %cliPrefs; # stores style preferences for each client package
119              
120             # DD print-style options/methods/package-vars/attributes.
121             # Theyre delegated to the inner DD object, and 'importable' too.
122              
123             my @styleopts; # used to validate methods in Set()
124              
125             # 5.00503 shipped with DD v2.101
126             @styleopts = qw( indent purity pad varname useqq terse freezer
127             toaster deepcopy quotekeys bless );
128              
129             push @styleopts, qw( maxdepth )
130             if $Data::Dumper::VERSION ge '2.102'; # with 5.6.1
131              
132             push @styleopts, qw( pair useperl sortkeys deparse )
133             if $Data::Dumper::VERSION ge '2.121'; # with 5.6.2
134              
135             # DD methods; also delegated
136             my @ddmethods = qw ( Seen Values Names Reset );
137              
138             # EzDD-specific importable style preferences
139             my @okPrefs = qw( autoprint init _ezdd_noreset );
140              
141             ##############
142             sub import {
143             # save EzDD client's preferences for use in new()
144 45     45   16492 my ($pkg, @args) = @_;
145 45         596 my ($prop, $val, %args);
146 0         0 my ($alias, @aliases, @ezdds);
147 45         726 my $caller = caller();
148              
149             # handle aliases, multiples allowed (feeping creaturism)
150              
151 45         258 foreach my $idx (grep {$args[$_] eq 'alias'} reverse 0..$#args) {
  69         198  
152 7         22 ($idx, $alias) = splice(@args, $idx, 2);
153 26     26   188 no strict 'refs';
  26         52  
  26         10472  
154 7         13 *{$alias.'::new'} = \&{$pkg.'::new'};
  7         52  
  7         24  
155 7         11 *{$alias.'::import'} = \&{$pkg.'::import'};
  7         31  
  7         23  
156 7         24 push @aliases, $alias;
157             }
158             # quietly accept 'imports' of things we export anyway
159 45         136 foreach my $idx (grep {$args[$_] =~ /[\$\&]?ezdump$/} reverse 0..$#args) {
  55         150  
160 3         7 splice(@args, $idx, 1);
161             }
162              
163 45         774 while ($prop = shift(@args)) {
164 26         64 $val = shift(@args);
165              
166 26 100       55 if (not grep { $_ eq $prop} @styleopts, @okPrefs) {
  494 100       881  
167 1         15 carp "unknown print-style: $prop";
168 1         614 next;
169             }
170             elsif ($prop ne 'init') {
171 18         48 $args{$prop} = $val;
172 18         70 push @ezdds, $val;
173             }
174             else {
175 7 100       48 carp "init arg must be a ref to a (scalar) variable"
176             unless ref($val) =~ /SCALAR/;
177              
178 7 100       670 carp "wont construct a new EzDD object into non-undef variable"
179             if defined $$val;
180              
181 7         493 $$val = Data::Dumper::EasyOO->new(%args);
182             }
183             }
184 45         113 $cliPrefs{$caller} = \%args; # save the allowed ones
185              
186             # export ezdump() unconditionally
187             # no warnings 'redefine';
188             local $SIG{__WARN__} = sub {
189 2 50   2   34 carp $@, @_ unless $_[0] =~ / redefined/;
190 45         288 };
191 26     26   160 no strict 'refs';
  26         64  
  26         8543  
192 45         186 my $ezdump = $pkg->new(%args);
193 45         70 ${$caller.'::ezdump'} = $ezdump; # export $ezdump = \&ezdump
  45         219  
194 45         62 *{$caller.'::ezdump'} = $ezdump; # export ezdump()
  45         287  
195              
196 45 100       144 return (1, \%args) if wantarray;
197 43 100       121 return (\%args) if defined wantarray;
198 42         17149 return;
199             }
200              
201             sub Set {
202             # sets internal state of private data dumper object
203 903     903 1 67464 my ($ezdd, %cfg) = @_;
204 903         1152 my $ddo = $ezdd;
205 903 100       3431 $ddo = $ezdd->($magic) if ref $ezdd eq __PACKAGE__;
206              
207 903 100       3709 $ddo->{_ezdd_noreset} = 1 if $cfg{_ezdd_noreset};
208              
209 903         1936 for my $item (keys %cfg) {
210             #print "$item => $cfg{$item}\n";
211 971         4189 my $attr = lc $item;
212 971         1503 my $meth = ucfirst $item;
213              
214 971 100       1457 if (grep {$attr eq $_} @styleopts) {
  15536 100       23744  
  416 100       744  
215 867         3259 $ddo->$meth($cfg{$item});
216             }
217 102         207 elsif (grep {$item eq $_} @ddmethods) {
218 70         241 $ddo->$meth($cfg{$item});
219             }
220             elsif (grep {$attr eq $_} @okPrefs) {
221 28         100 $ddo->{$attr} = $cfg{$item};
222             }
223 6         89 else { carp "illegal method <$item>" }
224             }
225 903         9855 return $ezdd;
226             }
227              
228 26     26   172 use vars '$AUTOLOAD';
  26         55  
  26         6773  
229              
230             sub AUTOLOAD {
231 694     694   159852 my ($ezdd, $arg) = @_;
232 694         3075 (my $meth = $AUTOLOAD) =~ s/.*:://;
233 694 50       1776 return if $meth eq 'DESTROY';
234 694         1444 my @vals = $ezdd->Set($meth => $arg);
235 694 100       4028 return $ezdd unless wantarray;
236 1         5 return $ezdd, @vals;
237             }
238              
239             sub pp {
240 8     8 1 4175 my ($ezdd, @data) = @_;
241 8         22 $ezdd->(@data);
242             }
243              
244             # Im ambivalent about this BEGIN block. Its only use is to suppress
245             # redefined warnings issued when re-do{}'g the file, ie when purposely
246             # avoiding use or require (see t/redefined.t). A more normal
247             # re-importing is already supressed in import(), by the same
248             # (localized) handler.
249              
250             local $SIG{__WARN__};
251             BEGIN {
252             $SIG{__WARN__} = sub {
253 0 0       0 carp $@, @_ unless $_[0] =~ / redefined/;
254 26     26   233 };
255 26         19921 *dump = \&pp; # causes warning if done outside begin block
256             }
257              
258             sub _ez_ddo {
259 1     1   385 my ($ezdd) = @_;
260 1         519 return $ezdd->($magic);
261             }
262              
263             my $_privatePrinter; # visible only to new and closure object it makes
264              
265             sub new {
266 122     122 1 187889 my ($cls, %cfg) = @_;
267 122   100     610 my $prefs = $cliPrefs{caller()} || {};
268              
269 122         1538 my $ddo = Data::Dumper->new([]); # inner obj w bogus data
270 122         3487 Set($ddo, %$prefs, %cfg); # ctor-params override pkg-config
271              
272             #print "EzDD::new() ", Data::Dumper::Dumper [$prefs, \%cfg];
273              
274             my $code = sub { # closure on $ddo
275 1189     1189   136401 &$_privatePrinter($ddo, @_);
276 122         764 };
277             # copy constructor
278 122   100     956 bless $code, ref $cls || $cls;
279            
280 122 100       284 if (ref $cls) {
281             # clone its settings
282 3         9 my $ddo = $cls->($magic);
283 3         7 my %styles;
284 3         44 @styles{@styleopts,@okPrefs} = @$ddo{@styleopts,@okPrefs};
285 3         22 $code->Set(%styles,%cfg);
286             }
287 122         1042 return $code;
288             }
289              
290             $_privatePrinter = \&__DONT_TOUCH_THIS;
291              
292             sub __DONT_TOUCH_THIS {
293 1190     1190   2616 my ($ddo, @args) = @_;
294              
295 1190 100       2955 unless ($ddo->{_ezdd_noreset}) {
296 1187         3209 $ddo->Reset; # clear seen
297 1187         11045 $ddo->Names([]); # clear labels
298 1187         10846 $ddo->Values([]); # clear data
299             }
300 1190 100       9879 if (@args == 1) {
    100          
301             # test for AUTOLOADs special access
302 1124 100 100     6456 return $ddo if defined $args[0] and $args[0] == $magic;
303            
304             # else Regular usage
305 339         713 $ddo->{todump} = \@args;
306             }
307             elsif (@args % 2) {
308             # cant be a hash, must be array of data
309 6         13 $ddo->{todump} = \@args;
310             }
311             else {
312             # possible labelled usage,
313             # check that all 'labels' are scalars
314            
315 60         231 my %rev = reverse @args;
316 60 100       112 if (grep {ref $_} values %rev) {
  80         218  
317             # odd elements are refs, must print as array
318 1         3 $ddo->{todump} = \@args;
319             }
320             else {
321 59         145 while (@args) {
322 78         91 push @{$ddo->{names}}, shift @args;
  78         198  
323 78         110 push @{$ddo->{todump}}, shift @args;
  78         325  
324             }
325             }
326             }
327 405 100       2032 PrintIt:
328             # return dump-str unless *void* context
329             return $ddo->Dump() if defined wantarray;
330            
331 12 100       46 unless (defined $ddo->{autoprint}) {
332 3         54 carp "called in void context, without autoprint defined\n";
333 3         3256 return;
334             }
335 9         18 my $auto = $ddo->{autoprint};
336             # do nothing if autoprint is 0
337 9 50       39 return unless $auto;
338            
339             # autoprint to STDOUT, STDERR, or HANDLE (IO or GLOB)
340            
341 9 100 66     136 if (ref $auto and (ref $auto eq 'GLOB' or $auto->can("print"))) {
    50 66        
    50          
342 6         28 print $auto $ddo->Dump();
343             }
344             elsif ($auto == 1) {
345 0         0 print STDOUT $ddo->Dump();
346             }
347             elsif ($auto == 2) {
348 0         0 print STDERR $ddo->Dump();
349             }
350             else {
351 3         45 carp "illegal autoprint value: $ddo->{autoprint}";
352             }
353 9         3234 return;
354             };
355              
356              
357             1;
358              
359             __END__