File Coverage

lib/Data/Pretty.pm
Criterion Covered Total %
statement 382 400 95.5
branch 199 232 85.7
condition 102 127 80.3
subroutine 23 25 92.0
pod 5 9 55.5
total 711 793 89.6


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## Data Dump Beautifier - ~/lib/Data/Pretty.pm
3             ## Version v0.1.6
4             ## Copyright(c) 2023 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest
6             ## Created 2023/08/06
7             ## Modified 2023/08/30
8             ## All rights reserved
9             ##
10             ##
11             ## This program is free software; you can redistribute it and/or modify it
12             ## under the same terms as Perl itself.
13             ##----------------------------------------------------------------------------
14             package Data::Pretty;
15             BEGIN
16             {
17 16     16   1756854 use strict;
  16         200  
  16         502  
18 16     16   105 use warnings;
  16         30  
  16         693  
19 16         2637 use vars qw(
20             @EXPORT @EXPORT_OK $VERSION $DEBUG
21             %seen %refcnt @dump @fixup %require
22             $TRY_BASE64 @FILTERS $INDENT $LINEWIDTH $SHOW_UTF8 $CODE_DEPARSE
23 16     16   109 );
  16         36  
24 16     16   9913 use subs qq(dump);
  16         571  
  16         80  
25 16     16   20872 use overload ();
  16         16945  
  16         1245  
26 16     16   113 require Exporter;
27 16         90 *import = \&Exporter::import;
28 16         55 @EXPORT = qw( dd ddx );
29 16         45 @EXPORT_OK = qw( dump pp dumpf literal quote );
30 16         32 our $DEBUG = 0;
31 16         372 our $VERSION = 'v0.1.6';
32             };
33              
34 16     16   81 use strict;
  16         40  
  16         318  
35 16     16   71 use warnings;
  16         28  
  16         1420  
36              
37             $TRY_BASE64 = 50 unless defined $TRY_BASE64;
38             $INDENT = ' ' unless defined $INDENT;
39             $LINEWIDTH = 60 unless defined $LINEWIDTH;
40             $SHOW_UTF8 = 1 unless defined $SHOW_UTF8;
41             $CODE_DEPARSE = 1 unless defined $CODE_DEPARSE;
42              
43             {
44 16     16   114 no warnings 'once';
  16         39  
  16         57549  
45             *pp = \&dump;
46             }
47              
48             sub dd {
49 1     1 1 2018 print dump(@_), "\n";
50             }
51              
52             sub ddx {
53 2     2 1 51 my(undef, $file, $line) = caller;
54 2         12 $file =~ s,.*[\\/],,;
55 2         8 my $out = "$file:$line: " . dump(@_) . "\n";
56 2         346 $out =~ s/^/# /gm;
57 2         104 print $out;
58             }
59              
60             sub dump
61             {
62 112     112   28762 local %seen;
63 112         164 local %refcnt;
64 112         145 local %require;
65 112         178 local @fixup;
66              
67 112 100       681 require Data::Pretty::FilterContext if @FILTERS;
68              
69 112         168 my $name = "a";
70 112         143 my @dump;
71              
72 112         322 my $use_qw = &_use_qw( [@_] );
73 112         269 for my $v (@_) {
74             # my $val = _dump($v, $name, [], tied($v));
75 160         404 my $val = _dump(
76             $v,
77             name => $name,
78             idx => [],
79             dont_remember => tied($v),
80             use_qw => $use_qw,
81             );
82 160         379 push(@dump, [$name, $val]);
83             } continue {
84 160         302 $name++;
85             }
86              
87 112         170 my $out = "";
88 112 100       236 if (%require) {
89 5         19 for (sort keys %require) {
90 5         17 $out .= "require $_;\n";
91             }
92             }
93 112 100       225 if (%refcnt) {
94             # output all those with refcounts first
95 10         32 for (@dump) {
96 27         48 my $name = $_->[0];
97 27 100       71 if ($refcnt{$name}) {
98 10         46 $out .= "my \$$name = $_->[1];\n";
99 10         30 undef $_->[1];
100             }
101             }
102 10         28 for (@fixup) {
103 17         116 $out .= "$_;\n";
104             }
105             }
106              
107 112         195 my $paren = (@dump != 1);
108             my $formatted = format_list(
109             paren => $paren,
110             comment => undef,
111 112 100       263 values => [map {defined($_->[1]) ? $_->[1] : "\$" .$_->[0]} @dump],
  160         648  
112             use_qw => $use_qw,
113             );
114 112         321 my $has_qw = substr( $formatted, 0, 2 ) eq 'qw';
115 112 100 100     291 $out .= "(" if( $paren && !$has_qw );
116 112         203 $out .= $formatted;
117 112 100 100     256 $out .= ")" if( $paren && !$has_qw );
118              
119 112 100 100     392 if (%refcnt || %require) {
120 14         61 $out .= ";\n";
121 14         507 $out =~ s/^/$INDENT/gm;
122 14         124 $out = "do {\n$out}";
123             }
124              
125 112 50       291 print STDERR "$out\n" unless defined wantarray;
126 112         1800 $out;
127             }
128              
129             sub dumpf {
130 8     8 1 1830 require Data::Pretty::Filtered;
131 8         45 goto &Data::Pretty::Filtered::dump_filtered;
132             }
133              
134             sub format_list
135             {
136 130     130 0 409 my $opts = {@_};
137 130         264 my $paren = $opts->{paren};
138 130         180 my $comment = $opts->{comment};
139 130 100       302 my $indent_lim = $paren ? 0 : 1;
140 130 50       256 my $use_qw = defined( $opts->{use_qw} ) ? $opts->{use_qw} : 1;
141 130         165 my $values = $opts->{values};
142            
143 130 100       304 if (@$values > 3) {
144             # my $use_quotes = 0;
145             # can we use range operator to shorten the list?
146 12         15 my $i = 0;
147 12         49 while ($i < @$values) {
148 40         54 my $j = $i + 1;
149 40         57 my $v = $values->[$i];
150 40         80 while ($j < @$values) {
151             # NOTE: allow string increment too?
152 316 100 100     1320 if ($v eq "0" || $v =~ /^-?[1-9]\d{0,9}\z/) {
    100          
153 37         49 $v++;
154             }
155             elsif ($v =~ /^"([A-Za-z]{1,3}\d*)"\z/) {
156 266         419 $v = $1;
157 266         253 $v++;
158 266         304 $v = qq("$v");
159             }
160             else {
161 13         15 last;
162             }
163 303 100       429 last if $values->[$j] ne $v;
164 289         387 $j++;
165             }
166 40 100       102 if ($j - $i > 3) {
167 9         56 splice(@$values, $i, $j - $i, "$values->[$i] .. $values->[$j-1]");
168 9         30 $use_qw = 0;
169             }
170 40         73 $i++;
171             }
172             }
173              
174 130 100       269 if( $use_qw )
175             {
176 1         3 my @repl;
177 1         5 foreach my $v ( @$values )
178             {
179 3         14 ( my $v2 = $v ) =~ s/^\"|\"$//g;
180 3         6 push( @repl, $v2 );
181             }
182 1         3 @$values = @repl;
183             }
184              
185 130         292 my $tmp = "@$values";
186 130 100       233 my $sep = $use_qw ? ' ' : ', ';
187 130 100 33     621 if ($comment || (@$values > $indent_lim && (length($tmp) > $LINEWIDTH || $tmp =~ /\n/))) {
      66        
      66        
188 1 50       4 if( $use_qw )
189             {
190 0         0 my @lines;
191             my @buf;
192 0         0 foreach my $v ( @$values )
193             {
194 0 0 0     0 if( scalar( @buf ) && length( $INDENT . join( ' ', @buf, $v ) ) > $LINEWIDTH )
195             {
196 0         0 push( @lines, $INDENT . join( ' ', @buf ) );
197 0         0 @buf = ( $v );
198             }
199             else
200             {
201 0         0 push( @buf, $v );
202             }
203             }
204 0 0       0 push( @lines, $INDENT . join( ' ', @buf ) ) if( scalar( @buf ) );
205             return (
206 0 0       0 $comment
    0          
    0          
207             ? ( scalar( @lines ) > 1 ? "\n$INDENT" : '' ) . "# $comment" . ( scalar( @lines ) > 1 ? "\n" : '' )
208             : ''
209             ) . 'qw(' . "\n" . join("\n", @lines,"") . ')';
210             }
211             else
212             {
213 1         4 my @elem = @$values;
214 1         10 for (@elem) { s/^/$INDENT/gm; }
  1         8  
215 1 50       12 return "\n" . ($comment ? "$INDENT# $comment\n" : "") .
216             join(",\n", @elem, "");
217             }
218             } else {
219 129 100       576 return $use_qw ? 'qw( ' . join( $sep, @$values ) . ' )' : join($sep, @$values);
220             }
221             }
222              
223             sub fullname
224             {
225 41     41 0 85 my($name, $idx, $ref) = @_;
226 41         70 substr($name, 0, 0) = "\$";
227              
228 41         72 my @i = @$idx; # need copy in order to not modify @$idx
229 41 100 100     104 if ($ref && @i && $i[0] eq "\$") {
      100        
230 2         4 shift(@i); # remove one deref
231 2         2 $ref = 0;
232             }
233 41   100     187 while (@i && $i[0] eq "\$") {
234 5         8 shift @i;
235 5         14 $name = "\$$name";
236             }
237              
238 41         54 my $last_was_index;
239 41         90 for my $i (@i) {
240 35 100 100     178 if ($i eq "*" || $i eq "\$") {
    100          
241 7         10 $last_was_index = 0;
242 7         20 $name = "$i\{$name}";
243             } elsif ($i =~ s/^\*//) {
244 2         5 $name .= $i;
245 2         4 $last_was_index++;
246             } else {
247 26 100       105 $name .= "->" unless $last_was_index++;
248 26         62 $name .= $i;
249             }
250             }
251 41 100       99 $name = "\\$name" if $ref;
252 41         118 $name;
253             }
254              
255 0     0 1 0 sub literal { return( Data::Pretty::Literal->new( @_ ) ); }
256              
257             my %esc = (
258             "\a" => "\\a",
259             "\b" => "\\b",
260             "\t" => "\\t",
261             "\n" => "\\n",
262             "\f" => "\\f",
263             "\r" => "\\r",
264             "\e" => "\\e",
265             );
266              
267             # put a string value in double quotes
268             sub quote {
269 361     361 1 1358 local($_) = $_[0];
270             # If there are many '"' we might want to use qq() instead
271 361         677 s/([\\\"\@\$])/\\$1/g;
272 361 100       1252 return qq("$_") unless /[^\040-\176]/; # fast exit
273              
274 16         106 s/([\a\b\t\n\f\r\e])/$esc{$1}/g;
275              
276             # no need for 3 digits in escape for these
277 16         48 s/([\0-\037])(?!\d)/sprintf('\\%o',ord($1))/eg;
  1103         2222  
278              
279 16         62 s/([\0-\037\177-\377])/sprintf('\\x%02X',ord($1))/eg;
  393         839  
280 16 100       34 unless( $SHOW_UTF8 )
281             {
282 5         16 $_ =~ s/([^\040-\176])/sprintf('\\x{%X}',ord($1))/eg;
  105         258  
283             }
284              
285 16         115 return qq("$_");
286             }
287              
288             sub str {
289 315     315 0 341 my $opts = $_[1];
290 315 100       474 if (length($_[0]) > 20) {
291 14         26 for ($_[0]) {
292             # Check for repeated string
293 14 100       48 if (/^(.)\1\1\1/s) {
294             # seems to be a repeating sequence, let's check if it really is
295             # without backtracking
296 4 50       50858 unless (/[^\Q$1\E]/) {
297 4         11 my $base = quote($1);
298 4         5 my $repeat = length;
299 4         18 return "($base x $repeat)"
300             }
301             }
302             # Length protection because the RE engine will blow the stack [RT#33520]
303 10 100 66     109 if (length($_) < 16 * 1024 && /^(.{2,5}?)\1*\z/s) {
304 2         6 my $base = quote($1);
305 2         13 my $repeat = length($_)/length($1);
306 2         23 return "($base x $repeat)";
307             }
308             }
309             }
310              
311 309         427 local $_ = "e;
312             # local $_ = $opts->{use_qw} ? $_[0] : "e;
313              
314 309 100 100     627 if (length($_) > 40 && !/\\x\{/ && length($_) > (length($_[0]) * 2)) {
      100        
315             # too much binary data, better to represent as a hex/base64 string
316              
317             # Base64 is more compact than hex when string is longer than
318             # 17 bytes (not counting any require statement needed).
319             # But on the other hand, hex is much more readable.
320 3 100 66     41 if ($TRY_BASE64 && length($_[0]) > $TRY_BASE64 &&
      66        
      100        
      66        
321             (defined &utf8::is_utf8 && !utf8::is_utf8($_[0])) &&
322 1         8 eval { require MIME::Base64 })
323             {
324 1         3 $require{"MIME::Base64"}++;
325 1         12 return "MIME::Base64::decode(\"" .
326             MIME::Base64::encode($_[0],"") .
327             "\")";
328             }
329 2         43 return "pack(\"H*\",\"" . unpack("H*", $_[0]) . "\")";
330             }
331 306         451 return $_;
332             }
333              
334             sub tied_str {
335 80     80 0 119 my $tied = shift;
336 80 100       154 if ($tied) {
337 2 50       7 if (my $tied_ref = ref($tied)) {
338 2         8 $tied = "tied $tied_ref";
339             }
340             else {
341 0         0 $tied = "tied";
342             }
343             }
344 80         116 return $tied;
345             }
346              
347             sub _dump
348             {
349 1400     1400   1840 my $ref = ref $_[0];
350 1400 100       2323 my $rval = $ref ? $_[0] : \$_[0];
351 1400         1590 shift;
352 1400         3645 my $opts = {@_};
353              
354 1400         2826 my($name, $idx, $dont_remember, $pclass, $pidx) = @$opts{qw( name idx dont_remember pclass pidx )};
355              
356 1400         1513 my($class, $type, $id);
357 1400         2447 my $strval = overload::StrVal($rval);
358             # Parse $strval without using regexps, in order not to clobber $1, $2,...
359 1400 100       5696 if ((my $i = rindex($strval, "=")) >= 0) {
360 26         51 $class = substr($strval, 0, $i);
361 26         56 $strval = substr($strval, $i+1);
362             }
363 1400 50       2369 if ((my $i = index($strval, "(0x")) >= 0) {
364 1400         1853 $type = substr($strval, 0, $i);
365 1400         1839 $id = substr($strval, $i + 2, -1);
366             }
367             else {
368 0         0 die "Can't parse " . overload::StrVal($rval);
369             }
370 1400 50 33     2410 if ($] < 5.008 && $type eq "SCALAR") {
371 0 0       0 $type = "REF" if $ref eq "REF";
372             }
373 1400 50 0     1861 warn "\$$name(@$idx) ", ( $class || 'undef' ), " $type $id ($ref), strval=$strval" if $DEBUG;
374              
375 1400         2232 my $out;
376             my $comment;
377 1400         0 my $hide_keys;
378 1400 100       1905 if (@FILTERS) {
379 11         13 my $pself = "";
380 11 100       24 $pself = fullname("self", [@$idx[$pidx..(@$idx - 1)]]) if $pclass;
381 11         34 my $ctx = Data::Pretty::FilterContext->new($rval, $class, $type, $ref, $pclass, $pidx, $idx);
382 11         21 my @bless;
383 11         15 for my $filter (@FILTERS) {
384 11 100       24 if (my $f = $filter->($ctx, $rval)) {
385 6 100       42 if (my $v = $f->{object}) {
386 1         2 local @FILTERS;
387 1         30 $out = _dump(
388             $v,
389             name => $name,
390             idx => $idx,
391             dont_remember => 1,
392             );
393 1         2 $dont_remember++;
394             }
395 6 100       14 if (defined(my $c = $f->{bless})) {
396 1         1 push(@bless, $c);
397             }
398 6 100       13 if (my $c = $f->{comment}) {
399 1         2 $comment = $c;
400             }
401 6 100       10 if (defined(my $c = $f->{dump})) {
402 1         2 $out = $c;
403 1         2 $dont_remember++;
404             }
405 6 100       16 if (my $h = $f->{hide_keys}) {
406 2 50       8 if (ref($h) eq "ARRAY") {
407             $hide_keys = sub {
408 2     2   4 for my $k (@$h) {
409 2 100       9 return 1 if $k eq $_[0];
410             }
411 1         3 return 0;
412 2         11 };
413             }
414             }
415             }
416             }
417 11 100 66     52 push(@bless, "") if defined($out) && !@bless;
418 11 100       35 if (@bless) {
419 3         6 $class = shift(@bless);
420 3 50       16 warn "More than one filter callback tried to bless object" if @bless;
421             }
422             }
423              
424 1400 100       1911 unless ($dont_remember) {
425 1385 100       2329 if (my $s = $seen{$id}) {
426 19         42 my($sname, $sidx) = @$s;
427 19         29 $refcnt{$sname}++;
428 19   100     79 my $sref = fullname($sname, $sidx,
429             ($ref && $type eq "SCALAR"));
430 19 50       55 warn "SEEN: [\$$name(@$idx)] => [\$$sname(@$sidx)] ($ref,$sref)" if $DEBUG;
431 19 100       71 return $sref unless $sname eq $name;
432 4         7 $refcnt{$name}++;
433 4         12 push(@fixup, fullname($name,$idx)." = $sref");
434 4 100 66     23 return "do{my \$fix}" if @$idx && $idx->[-1] eq '$';
435 3         11 return "'fix'";
436             }
437 1366         4151 $seen{$id} = [$name, $idx];
438             }
439              
440 1381 100       2149 if ($class) {
441 27         48 $pclass = $class;
442 27         35 $pidx = @$idx;
443             }
444              
445 1381 100 100     3810 if (defined $out) {
    100 100        
    100          
    100          
    100          
    100          
    50          
446             # keep it
447             }
448             # NOTE: scalar, ref or regexp
449             elsif ($type eq "SCALAR" || $type eq "REF" || $type eq "REGEXP") {
450 1246 100       1514 if ($ref) {
451             # NOTE: regexp
452 32 100 100     97 if ($class && $class eq "Regexp") {
453 9         16 my $v = "$rval";
454              
455 9         10 my $mod = "";
456 9 50       40 if ($v =~ /^\(\?\^?([msix-]*):([\x00-\xFF]*)\)\z/) {
457 9         28 $mod = $1;
458 9         15 $v = $2;
459 9         14 $mod =~ s/-.*//;
460             }
461              
462 9         14 my $sep = '/';
463 9         15 my $sep_count = ($v =~ tr/\///);
464 9 100       16 if ($sep_count) {
465             # see if we can find a better one
466 4         6 for ('|', ',', ':', '#') {
467 10         419 my $c = eval "\$v =~ tr/\Q$_\E//";
468             #print "SEP $_ $c $sep_count\n";
469 10 100       38 if ($c < $sep_count) {
470 3         5 $sep = $_;
471 3         3 $sep_count = $c;
472 3 50       8 last if $sep_count == 0;
473             }
474             }
475             }
476 9         70 $v =~ s/\Q$sep\E/\\$sep/g;
477              
478 9         25 $out = "qr$sep$v$sep$mod";
479 9         14 undef($class);
480             }
481             else {
482 23 100       102 delete $seen{$id} if $type eq "SCALAR"; # will be seen again shortly
483 23         351 my $val = _dump(
484             $$rval,
485             name => $name,
486             idx => [@$idx, "\$"],
487             dont_remember => 0,
488             pclass => $pclass,
489             pidx => $pidx,
490             );
491 23 100       88 $out = $class ? "do{\\(my \$o = $val)}" : "\\$val";
492             }
493             # NOTE; regular string
494             } else {
495 1214 100   1   2750 if (!defined $$rval) {
  1 100       1459  
  1 100       15  
  1         16  
496 3         6 $out = "undef";
497             }
498             elsif ($$rval =~ /^-?(?:nan|inf)/i) {
499 4         7 $out = str($$rval);
500             }
501 16     16   132 elsif (do {no warnings 'numeric'; $$rval + 0 eq $$rval}) {
  16         52  
  16         33443  
  1207         33613  
502 896         1014 $out = $$rval;
503             }
504             else {
505 311         524 $out = str($$rval, $opts);
506             # $out = str($$rval);
507             }
508 1214 100 100     2100 if ($class && !@$idx) {
509             # Top is an object, not a reference to one as perl needs
510 1         5 $refcnt{$name}++;
511 1         5 my $obj = fullname($name, $idx);
512 1         3 my $cl = quote($class);
513 1         6 push(@fixup, "bless \\$obj, $cl");
514             }
515             }
516             }
517             # NOTE: glob
518             elsif ($type eq "GLOB") {
519 40 100       60 if ($ref) {
520 6         15 delete $seen{$id};
521 6         48 my $val = _dump(
522             $$rval,
523             name => $name,
524             idx => [@$idx, "*"],
525             dont_remember => 0,
526             pclass => $pclass,
527             pidx => $pidx,
528             );
529 6         13 $out = "\\$val";
530 6 100       31 if ($out =~ /^\\\*Symbol::/) {
531 4         10 $require{Symbol}++;
532 4         7 $out = "Symbol::gensym()";
533             }
534             } else {
535 34         95 my $val = "$$rval";
536 34         69 $out = "$$rval";
537              
538 34         57 for my $k (qw(SCALAR ARRAY HASH)) {
539 102         142 my $gval = *$$rval{$k};
540 102 100       169 next unless defined $gval;
541 41 100 100     118 next if $k eq "SCALAR" && ! defined $$gval; # always there
542 12         15 my $f = scalar @fixup;
543 12         24 push(@fixup, "RESERVED"); # overwritten after _dump() below
544 12         106 $gval = _dump(
545             $gval,
546             name => $name,
547             idx => [@$idx, "*{$k}"],
548             dont_remember => 0,
549             pclass => $pclass,
550             pidx => $pidx,
551             );
552 12         33 $refcnt{$name}++;
553 12         30 my $gname = fullname($name, $idx);
554 12         67 $fixup[$f] = "$gname = $gval"; #XXX indent $gval
555             }
556             }
557             }
558             # NOTE: array
559             elsif ($type eq "ARRAY") {
560 18         34 my @vals;
561 18         48 my $tied = tied_str(tied(@$rval));
562             # Quick check if we are dealing with a simple array of words/terms
563             # and thus if we can use qw( .... ) instead of ( "some", "thing", "else" )
564 18         36 my $use_qw = &_use_qw( $rval );
565              
566 18         37 my $i = 0;
567 18         42 for my $v (@$rval) {
568 291         950 push(@vals, _dump(
569             $v,
570             name => $name,
571             idx => [@$idx, "[$i]"],
572             dont_remember => $tied,
573             pclass => $pclass,
574             pidx => $pidx,
575             use_qw => $use_qw,
576             ));
577 291         472 $i++;
578             }
579 18         59 $out = "[" . format_list(
580             paren => 1,
581             comment => $tied,
582             values => \@vals,
583             use_qw => $use_qw,
584             ) . "]";
585             }
586             # NOTE: hash
587             elsif ($type eq "HASH") {
588 62         91 my(@keys, @vals);
589 62         121 my $tied = tied_str(tied(%$rval));
590              
591             # statistics to determine variation in key lengths
592 62         77 my $kstat_max = 0;
593 62         70 my $kstat_sum = 0;
594 62         64 my $kstat_sum2 = 0;
595              
596 62         459 my @orig_keys = keys %$rval;
597 62 100       181 if ($hide_keys) {
598 1         8 @orig_keys = grep !$hide_keys->($_), @orig_keys;
599             }
600 62         76 my $text_keys = 0;
601 62         101 for (@orig_keys) {
602 50 100       264 $text_keys++, last unless /^[-+]?(?:0|[1-9]\d*)(?:\.\d+)?\z/;
603             }
604              
605 62 100       122 if ($text_keys) {
606 43         159 @orig_keys = sort { lc($a) cmp lc($b) } @orig_keys;
  4936         5319  
607             }
608             else {
609 19         46 @orig_keys = sort { $a <=> $b } @orig_keys;
  4         13  
610             }
611              
612             # my $quote;
613 62         110 my $need_quotes = {};
614 62         106 for my $key (@orig_keys) {
615 907 100       1733 next if $key =~ /^-?[a-zA-Z_]\w*\z/;
616 33 100       65 next if $key =~ /^-?[1-9]\d{0,8}\z/;
617 29 100       54 next if $key =~ /^-?\d{1,9}\.\d+\z/;
618             # $quote++;
619 26         48 $need_quotes->{ $key }++;
620             # last;
621             }
622              
623 62         92 my $need_breakdown = 0;
624 62         116 for my $key (@orig_keys) {
625 907         995 my $orig = $key;
626 907         1258 my $val = \$rval->{$key}; # capture value before we modify $key
627             # $key = quote($key) if $quote;
628 907 100       1363 $key = quote($key) if $need_quotes->{ $key };
629 907 100       1336 $kstat_max = length($key) if length($key) > $kstat_max;
630 907         926 $kstat_sum += length($key);
631 907         1152 $kstat_sum2 += length($key)*length($key);
632              
633 907         1094 push(@keys, $key);
634             # push(@vals, _dump($$val, $name, [@$idx, "{$key}"], $tied, $pclass, $pidx));
635 907         2829 my $this = _dump(
636             $$val,
637             name => $name,
638             idx => [@$idx, "{$key}"],
639             dont_remember => $tied,
640             pclass => $pclass,
641             pidx => $pidx,
642             );
643 907         975 my $this_type;
644 907 100       1550 if ((my $i = index(overload::StrVal($$val), "(0x")) >= 0) {
645 47         257 $this_type = substr(overload::StrVal($$val), 0, $i);
646             }
647             # Our child element is also an HASH, and if it is not empty, this would become too much of a cluttered structure to print in just one line.
648 907 100 100     3791 if( defined( $this_type ) && $this_type eq 'HASH' && scalar( keys( %{$rval->{$orig}} ) ) )
  26   100     72  
649             {
650 15         18 $need_breakdown++;
651             }
652 907         1692 push( @vals, $this );
653             }
654 62         96 my $nl = "";
655 62         76 my $klen_pad = 0;
656 62         413 my $tmp = "@keys @vals";
657 62 100 66     372 if (length($tmp) > $LINEWIDTH || $tmp =~ /\n/ || $tied || $need_breakdown) {
      100        
      66        
658 23         33 $nl = "\n";
659             }
660 62         95 $out = "{$nl";
661 62 100       118 $out .= "$INDENT# $tied$nl" if $tied;
662 62         128 while (@keys) {
663 907         1057 my $key = shift @keys;
664 907         1020 my $val = shift @vals;
665 907 50       1714 my $vpad = $INDENT . (" " x ($klen_pad ? $klen_pad + 4 : 0));
666 907         1413 $val =~ s/\n/\n$vpad/gm;
667 907 100       1187 my $kpad = $nl ? $INDENT : " ";
668 907 50 66     1979 $key .= " " x ($klen_pad - length($key)) if $nl && $klen_pad > length($key);
669 907         2013 $out .= "$kpad$key => $val,$nl";
670             }
671 62 100       230 $out =~ s/,$/ / unless $nl;
672 62         189 $out .= "}";
673             }
674             # NOTE: code
675             elsif ($type eq "CODE") {
676 2 100 66     6 if( $CODE_DEPARSE && eval { require B::Deparse } )
  1         9  
677             {
678             # -sC to cuddle elsif, else and continue
679             # -si4 indent by 4 spaces (default)
680             # -p use extra parenthesis
681             # my $deparse = B::Deparse->new("-p", "-sC");
682 1         66 my $deparse = B::Deparse->new;
683 1         2773 my $code = $deparse->coderef2text( $rval );
684             # Don't let our environment influence the code
685 1         23 1 while $code =~ s/^\{[\s\n]+use\s(warnings|strict);\n/\{\n/gs;
686 1         11 $out = 'sub ' . $code;
687             }
688             else
689             {
690 1         2 $out = 'sub { ... }';
691             }
692             }
693             # NOTE: vstring
694             elsif ($type eq "VSTRING") {
695 11 100       54 $out = sprintf +($ref ? '\v%vd' : 'v%vd'), $$rval;
696             }
697             else {
698 0         0 warn "Can't handle $type data";
699 0         0 $out = "'#$type#'";
700             }
701              
702 1381 100 100     2208 if ($class && $ref) {
703 14 50       53 if( $class eq 'Data::Pretty::Literal' )
704             {
705 0         0 $out = $$rval;
706             }
707             else
708             {
709 14         52 $out = "bless($out, " . quote($class) . ")";
710             }
711             }
712 1381 100       1751 if ($comment) {
713 1         6 $comment =~ s/^/# /gm;
714 1 50       5 $comment .= "\n" unless $comment =~ /\n\z/;
715 1         4 $comment =~ s/^#[ \t]+\n/\n/;
716 1         3 $out = "$comment$out";
717             }
718 1381         3291 return $out;
719             }
720              
721             sub _use_qw
722             {
723 130     130   212 my $rval = shift( @_ );
724             # Quick check if we are dealing with a simple array of words/terms
725             # and thus if we can use qw( .... ) instead of ( "some", "thing", "else" )
726 130         158 my $use_qw = 1;
727 130         149 my $only_numbers = 0;
728 130         227 foreach my $v ( @$rval )
729             {
730 433 100 100     1657 if( !defined( $v ) ||
      100        
      66        
      100        
731             ref( $v ) ||
732             substr( overload::StrVal( \$v ), 0, 7 ) eq 'VSTRING' ||
733             # See perlop/"qw/STRING/" section
734             ( !ref( $v ) && $v =~ /[\,\\\#[:blank:]\h\v\a\b\t\n\f\r\e\@\"\$]/ ) )
735             {
736 72         228 $use_qw = 0;
737 72         121 last;
738             }
739 361 100       3184 $only_numbers++ if( $v =~ /^[-+]?(?:0|[1-9]\d*)(?:\.\d+)?\z/ );
740             }
741             # Don't use qw() if we are only dealing with numbers
742 130 100 100     472 $use_qw = 0 if( $only_numbers == scalar( @$rval ) || scalar( @$rval ) == 1 );
743 130         220 return( $use_qw );
744             }
745              
746             {
747             package
748             Data::Pretty::Literal;
749             sub new
750             {
751 0     0   0 my $this = shift( @_ );
752 0         0 my $str = shift( @_ );
753 0 0 0     0 return( bless( ( ref( $str ) eq 'SCALAR' ? $str : \$str ) => ( ref( $this ) || $this ) ) );
754             }
755             }
756              
757             1;
758             # NOTE: POD
759             __END__