| File: | blib/lib/Data/Dumper/EasyOO.pm |
| Coverage: | 93.0% |
| line | stmt | branch | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | #!perl | |||||
| 2 | ||||||
| 3 | package Data::Dumper::EasyOO; | |||||
| 4 | 32 32 32 | 314 233 178 | use Data::Dumper(); | |||
| 5 | 32 32 32 | 381 162 391 | use Carp 'carp'; | |||
| 6 | ||||||
| 7 | 32 32 32 | 633 168 165 | use 5.005_03; | |||
| 8 | 32 32 32 | 339 170 321 | use vars qw($VERSION); | |||
| 9 | $VERSION = '0.04_03'; | |||||
| 10 | ||||||
| 11 - 66 | =head1 NAME
Data::Dumper::EasyOO - wraps DD for easy use of various printing styles
=head1 ABSTRACT
EzDD's main goals are to make it easy to label data that you
print/dump, and to make it easy to one or more dumper objects, and one
or more print styles with each one.
Its designed to give you maximum control with a minimum of keystrokes.
At use-time, you can specify default print style(s), and can also
create 1 or more EzDD printer objects to use those styles. Each
printer object's style can be adjusted thereafter.
EzDD has similar goals as its step-sibling, Data::Dumper::Simple, but
differs in that it does not use source filtering, and it exposes
essentially all of DD's functionality, but with an easier interface.
=head1 SYNOPSIS
my $ezdd; # declare a default object (optional)
use Data::Dumper::EasyOO
(
alias => EzDD, # a temporary top-level-name alias
# set some print-style defaults
indent => 1, # change DD's default from 2
sortkeys => 1, # a personal favorite
# autoconstruct a printer obj (calls EzDD->new) with the defaults
init => \$ezdd, # var must be undef b4 use
# set some more default print-styles
terse => 1, # change DD's default of 0
autoprint => $fh, # prints to $fh when you $ezdd->(\%something);
# autoconstruct a 2nd printer object, using current print-styles
init => \our $ez2, # var must be undef b4 use
);
$ezdd->(p1 => $person); # print as '$p1 => ...'
my $foo = EzDD->new(%style) # create a printer, via alias, w new style
->(there => $place); # and print with it too.
$ez2-> (p2 => $person); # dump w $ez2, use its style
$foo->(here => $where); # dump w $foo style (use 2 w/o interference)
$foo->Set(%morestyle); # change style at runtime
$foo->($_) foreach @things; # print many things
=cut | |||||
| 67 | ||||||
| 68 | ; | |||||
| 69 | ############## | |||||
| 70 | # this (private) reference is passed to the closure to recover | |||||
| 71 | # the underlying Data::Dumper object | |||||
| 72 | my $magic = []; | |||||
| 73 | my %cliPrefs; # stores style preferences for each client package | |||||
| 74 | ||||||
| 75 | # DD print-style options/methods/package-vars/attributes. | |||||
| 76 | # Theyre delegated to the inner DD object, and 'importable' too. | |||||
| 77 | ||||||
| 78 | my @styleopts; # used to validate methods in Set() | |||||
| 79 | ||||||
| 80 | # 5.00503 shipped with DD v2.101 | |||||
| 81 | @styleopts = qw( indent purity pad varname useqq terse freezer | |||||
| 82 | toaster deepcopy quotekeys bless ); | |||||
| 83 | ||||||
| 84 | push @styleopts, qw( maxdepth ) | |||||
| 85 | if $Data::Dumper::VERSION ge '2.102'; # with 5.6.1 | |||||
| 86 | ||||||
| 87 | push @styleopts, qw( pair useperl sortkeys deparse ) | |||||
| 88 | if $Data::Dumper::VERSION ge '2.121'; # with 5.6.2 | |||||
| 89 | ||||||
| 90 | # DD methods; also delegated | |||||
| 91 | my @ddmethods = qw ( Seen Values Names Reset ); | |||||
| 92 | ||||||
| 93 | # EzDD-specific importable style preferences | |||||
| 94 | my @okPrefs = qw( autoprint init ); | |||||
| 95 | ||||||
| 96 | ############## | |||||
| 97 | sub import { | |||||
| 98 | # save EzDD client's preferences for use in new() | |||||
| 99 | 54 | 564 | my ($pkg, @args) = @_; | |||
| 100 | 54 | 523 | my ($prop, $val, %args); | |||
| 101 | ||||||
| 102 | # handle aliases, multiples allowed (feeping creaturism) | |||||
| 103 | ||||||
| 104 | 54 88 | 641 643 | foreach my $idx (grep {$args[$_] eq 'alias'} reverse 0..$#args) { | |||
| 105 | 10 | 84 | ($idx, $alias) = splice(@args, $idx, 2); | |||
| 106 | 32 32 32 | 355 169 438 | no strict 'refs'; | |||
| 107 | #*{$alias.'::'} = *{$pkg.'::'}; | |||||
| 108 | 10 10 10 | 54 115 72 | *{$alias.'::new'} = *{$pkg.'::new'}; | |||
| 109 | } | |||||
| 110 | ||||||
| 111 | 54 | 520 | while ($prop = shift(@args)) { | |||
| 112 | 34 | 191 | $val = shift(@args); | |||
| 113 | ||||||
| 114 | 34 612 | 201 3796 | if (not grep { $_ eq $prop} @styleopts, @okPrefs) { | |||
| 115 | 2 | 17 | carp "unknown print-style: $prop"; | |||
| 116 | 2 | 36 | next; | |||
| 117 | } | |||||
| 118 | elsif ($prop ne 'init') { | |||||
| 119 | 18 | 231 | $args{$prop} = $val; | |||
| 120 | } | |||||
| 121 | else { | |||||
| 122 | 14 | 134 | carp "init arg must be a ref to a (scalar) variable" | |||
| 123 | unless ref($val) =~ /SCALAR/; | |||||
| 124 | ||||||
| 125 | 14 | 120 | carp "wont construct a new EzDD object into non-undef variable" | |||
| 126 | if defined $$val; | |||||
| 127 | ||||||
| 128 | 14 | 125 | $$val = Data::Dumper::EasyOO->new(%args); | |||
| 129 | } | |||||
| 130 | } | |||||
| 131 | 54 | 583 | $cliPrefs{caller()} = {%args}; # save the allowed ones | |||
| 132 | #print "EzDD client cache: ", Data::Dumper::Dumper \%cliPrefs; | |||||
| 133 | } | |||||
| 134 | ||||||
| 135 | sub Set { | |||||
| 136 | # sets internal state of private data dumper object | |||||
| 137 | 1642 | 11584 | my ($ezdd, %cfg) = @_; | |||
| 138 | 1642 | 8580 | my $ddo = $ezdd; | |||
| 139 | 1642 | 16309 | $ddo = $ezdd->($magic) if ref $ezdd eq __PACKAGE__; | |||
| 140 | ||||||
| 141 | 1642 | 11875 | for my $item (keys %cfg) { | |||
| 142 | #print "$item => $cfg{$item}\n"; | |||||
| 143 | 1824 | 11520 | my $attr = lc $item; | |||
| 144 | 1824 | 10126 | my $meth = ucfirst $item; | |||
| 145 | ||||||
| 146 | 1824 29184 712 | 9879 179200 4540 | if (grep {$attr eq $_} @styleopts) { | |||
| 147 | 1646 | 13289 | $ddo->$meth($cfg{$item}); | |||
| 148 | } | |||||
| 149 | 76 | 513 | elsif (grep {$item eq $_} @ddmethods) { | |||
| 150 | 140 | 1090 | $ddo->$meth($cfg{$item}); | |||
| 151 | } | |||||
| 152 | elsif (grep {$attr eq $_} @okPrefs) { | |||||
| 153 | 26 | 280 | $ddo->{$attr} = $cfg{$item}; | |||
| 154 | } | |||||
| 155 | 12 | 98 | else { carp "illegal method <$item>" } | |||
| 156 | } | |||||
| 157 | 1642 | 12675 | $ezdd; | |||
| 158 | } | |||||
| 159 | ||||||
| 160 | sub AUTOLOAD { | |||||
| 161 | 1462 | 9537 | my ($ezdd, $arg) = @_; | |||
| 162 | 1462 | 10392 | (my $meth = $AUTOLOAD) =~ s/.*:://; | |||
| 163 | 1462 | 9608 | return if $meth eq 'DESTROY'; | |||
| 164 | 1384 | 8970 | my @vals = $ezdd->Set($meth => $arg); | |||
| 165 | 1384 | 14262 | return $ezdd unless wantarray; | |||
| 166 | 2 | 16 | return $ezdd, @vals; | |||
| 167 | } | |||||
| 168 | ||||||
| 169 | #my $_privateFunc; | |||||
| 170 | ||||||
| 171 | sub new { | |||||
| 172 | 108 | 2142 | my ($cls, %cfg) = @_; | |||
| 173 | 108 | 932 | my $prefs = $cliPrefs{caller()} || {}; | |||
| 174 | ||||||
| 175 | 108 | 957 | my $ddo = Data::Dumper->new([]); # inner obj w bogus data | |||
| 176 | 108 | 5629 | Set($ddo, %$prefs, %cfg); # ctor-config overrides pkg-config | |||
| 177 | ||||||
| 178 | #print "EzDD::new() ", Data::Dumper::Dumper [$prefs, \%cfg]; | |||||
| 179 | ||||||
| 180 | my $code = sub { # closure on $ddo | |||||
| 181 | 2242 | 15799 | my @args = @_; | |||
| 182 | ||||||
| 183 | 2242 | 17717 | unless ($ddo->{_ezdd_noreset}) { | |||
| 184 | 2242 | 15655 | $ddo->Reset; # clear seen | |||
| 185 | 2242 | 18584 | $ddo->Names([]); # clear labels | |||
| 186 | } | |||||
| 187 | 2242 | 20895 | if (@args == 1) { | |||
| 188 | # test for AUTOLOADs special access | |||||
| 189 | 2142 | 41625 | return $ddo if defined $args[0] and $args[0] eq $magic; | |||
| 190 | ||||||
| 191 | # else Regular usage | |||||
| 192 | 602 | 4001 | $ddo->{todump} = \@args; | |||
| 193 | 602 | 4494 | goto PrintIt; | |||
| 194 | } | |||||
| 195 | # else | |||||
| 196 | 100 | 700 | if (@args % 2) { | |||
| 197 | # cant be a hash, must be array of data | |||||
| 198 | 12 | 76 | $ddo->{todump} = \@args; | |||
| 199 | 12 | 140 | goto PrintIt; | |||
| 200 | } | |||||
| 201 | else { | |||||
| 202 | # possible labelled usage, | |||||
| 203 | # check that all 'labels' are scalars | |||||
| 204 | ||||||
| 205 | 88 | 829 | my %rev = reverse @args; | |||
| 206 | 88 122 | 566 840 | if (grep {ref $_} values %rev) { | |||
| 207 | # odd elements are refs, must print as array | |||||
| 208 | 0 | 0 | $ddo->{todump} = \@args; | |||
| 209 | 0 | 0 | goto PrintIt; | |||
| 210 | } | |||||
| 211 | 88 | 481 | my (@labels,@vals); | |||
| 212 | 88 | 650 | while (@args) { | |||
| 213 | 122 | 738 | push @labels, shift @args; | |||
| 214 | 122 | 1336 | push @vals, shift @args; | |||
| 215 | } | |||||
| 216 | 88 | 565 | $ddo->{names} = \@labels; | |||
| 217 | 88 | 546 | $ddo->{todump} = \@vals; | |||
| 218 | 88 | 1096 | goto PrintIt; | |||
| 219 | } | |||||
| 220 | 702 | 6402 | PrintIt: | |||
| 221 | # return dump-str unless void context | |||||
| 222 | return $ddo->Dump() if defined wantarray; | |||||
| 223 | ||||||
| 224 | 22 | 188 | my $auto = (defined $ddo->{autoprint}) ? $ddo->{autoprint} : ''; | |||
| 225 | ||||||
| 226 | 22 | 175 | unless ($auto) { | |||
| 227 | 6 | 50 | carp "called in void context, without autoprint set"; | |||
| 228 | 6 | 67 | return; | |||
| 229 | } | |||||
| 230 | # autoprint to STDOUT, STDERR, or HANDLE (IO or GLOB) | |||||
| 231 | ||||||
| 232 | 16 | 324 | if ($auto == 1) { | |||
| 233 | 0 | 0 | print STDOUT $ddo->Dump(); | |||
| 234 | } | |||||
| 235 | elsif ($auto == 2) { | |||||
| 236 | 0 | 0 | print STDERR $ddo->Dump(); | |||
| 237 | } | |||||
| 238 | elsif (ref $auto and (ref $auto eq 'GLOB' or $auto->can("print"))) { | |||||
| 239 | 14 | 127 | print $auto $ddo->Dump(); | |||
| 240 | } | |||||
| 241 | else { | |||||
| 242 | 2 | 42 | carp "illegal autoprint value: $ddo->{autoprint}"; | |||
| 243 | } | |||||
| 244 | 16 | 1150 | return; | |||
| 245 | 108 | 1934 | }; | |||
| 246 | ||||||
| 247 | # copy constructor | |||||
| 248 | 108 | 1436 | bless $code, ref $cls || $cls; | |||
| 249 | ||||||
| 250 | 108 | 749 | if (ref $cls) { | |||
| 251 | # clone its settings | |||||
| 252 | 6 | 38 | my $ddo = $cls->($magic); | |||
| 253 | 6 | 34 | my %styles; | |||
| 254 | 6 | 143 | @styles{@styleopts,@okPrefs} = @$ddo{@styleopts,@okPrefs}; | |||
| 255 | 6 | 82 | $code->Set(%styles,%cfg); | |||
| 256 | } | |||||
| 257 | 108 | 862 | return $code; | |||
| 258 | } | |||||
| 259 | ||||||
| 260 | sub pp { | |||||
| 261 | 16 | 103 | my ($ezdd, @data) = @_; | |||
| 262 | 16 | 99 | $ezdd->(@data); | |||
| 263 | } | |||||
| 264 | ||||||
| 265 | *dump = \&pp; | |||||
| 266 | ||||||
| 267 | 1; | |||||
| 268 | ||||||