File Coverage

lib/Data/Pretty.pm
Criterion Covered Total %
statement 379 392 96.6
branch 198 228 86.8
condition 102 124 82.2
subroutine 23 23 100.0
pod 4 8 50.0
total 706 775 91.1


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