File Coverage

blib/lib/Data/Printer/Filter/HASH.pm
Criterion Covered Total %
statement 72 74 97.3
branch 30 34 88.2
condition 22 30 73.3
subroutine 7 7 100.0
pod 0 1 0.0
total 131 146 89.7


line stmt bran cond sub pod time code
1             package Data::Printer::Filter::HASH;
2 35     35   257 use strict;
  35         78  
  35         1019  
3 35     35   179 use warnings;
  35         80  
  35         1186  
4 35     35   226 use Data::Printer::Filter;
  35         69  
  35         207  
5 35     35   207 use Data::Printer::Common;
  35         70  
  35         946  
6 35     35   229 use Scalar::Util ();
  35         74  
  35         29083  
7              
8             filter 'HASH' => \&parse;
9              
10              
11             sub parse {
12 81     81 0 181 my ($hash_ref, $ddp) = @_;
13 81         150 my $tied = '';
14 81 100 100     213 if ($ddp->show_tied and my $tie = ref tied %$hash_ref) {
15 2         15 $tied = " (tied to $tie)";
16             }
17 81 50 33     259 return $ddp->maybe_colorize('{', 'brackets')
18             . ' ' . $ddp->maybe_colorize('...', 'hash')
19             . ' ' . $ddp->maybe_colorize('}', 'brackets')
20             . $tied
21             if $ddp->max_depth && $ddp->current_depth >= $ddp->max_depth;
22              
23 81         278 my @src_keys = keys %$hash_ref;
24 81 100       316 return $ddp->maybe_colorize('{}', 'brackets') . $tied unless @src_keys;
25 69 100       207 @src_keys = Data::Printer::Common::_nsort(@src_keys) if $ddp->sort_keys;
26              
27 69         158 my $len = 0;
28 69   100     204 my $align_keys = $ddp->multiline && $ddp->align_hash;
29              
30 69         254 my @i = Data::Printer::Common::_fetch_indexes_for(\@src_keys, 'hash', $ddp);
31              
32 69         133 my %processed_keys;
33             # first pass, preparing keys and getting largest key size:
34 69         149 foreach my $idx (@i) {
35 156 100       333 next if ref $idx;
36 149         260 my $raw_key = $src_keys[$idx];
37 149         364 my $colored_key = Data::Printer::Common::_process_string($ddp, $raw_key, 'hash');
38 149         360 my $new_key = Data::Printer::Common::_colorstrip($colored_key);
39              
40 149 100       327 if (_needs_quote($ddp, $raw_key, $new_key)) {
41 2         5 my $quote_char = $ddp->scalar_quotes;
42             # foo'bar ==> 'foo\'bar'
43 2 50       8 if (index($new_key, $quote_char) >= 0) {
44 0         0 $new_key =~ s{$quote_char}{\\$quote_char}g;
45 0         0 $colored_key =~ s{$quote_char}{\\$quote_char}g;
46             }
47 2         5 $new_key = $quote_char . $new_key . $quote_char;
48 2         5 $colored_key = $ddp->maybe_colorize($quote_char, 'quotes')
49             . $colored_key
50             . $ddp->maybe_colorize($quote_char, 'quotes')
51             ;
52             }
53 149         690 $processed_keys{$idx} = {
54             raw => $raw_key,
55             colored => $colored_key,
56             nocolor => $new_key,
57             };
58 149 100       392 if ($align_keys) {
59 95         147 my $l = length $new_key;
60 95 100       294 $len = $l if $l > $len;
61             }
62             }
63             # second pass, traversing and rendering:
64 69         231 $ddp->indent;
65 69         117 my $total_keys = scalar @i; # yes, counting messages so ',' appear in between.
66             #keys %processed_keys;
67 69         182 my $string = $ddp->maybe_colorize('{', 'brackets');
68 69         178 foreach my $idx (@i) {
69 156         275 $total_keys--;
70             # $idx is a message to display, not a real index
71 156 100       346 if (ref $idx) {
72 7         17 $string .= $ddp->newline . $$idx;
73 7         16 next;
74             }
75 149         343 my $key = $processed_keys{$idx};
76              
77 149         387 my $original_varname = $ddp->current_name;
78             # update 'var' to 'var{key}':
79             $ddp->current_name(
80             $original_varname
81             . ($ddp->arrows eq 'all' || ($ddp->arrows eq 'first' && $ddp->current_depth == 1) ? '->' : '')
82 149 100 66     385 . '{' . $key->{nocolor} . '}'
83             );
84              
85 149         311 my $padding = $len - length($key->{nocolor});
86 149 100       327 $padding = 0 if $padding < 0;
87             $string .= $ddp->newline
88             . $key->{colored}
89 149         334 . (' ' x $padding)
90             . $ddp->maybe_colorize($ddp->hash_separator, 'separator')
91             ;
92              
93             # scalar references should be re-referenced to gain
94             # a '\' in front of them.
95 149         434 my $ref = ref $hash_ref->{$key->{raw}};
96 149 100 100     699 if ( $ref && $ref eq 'SCALAR' ) {
    100 100        
97 2         9 $string .= $ddp->parse(\$hash_ref->{ $key->{raw} }, tied_parent => !!$tied);
98             }
99             elsif ( $ref && $ref ne 'REF' ) {
100 45         167 $string .= $ddp->parse( $hash_ref->{ $key->{raw} }, tied_parent => !!$tied);
101             } else {
102 102         378 $string .= $ddp->parse(\$hash_ref->{ $key->{raw} }, tied_parent => !!$tied);
103             }
104              
105 149 100 66     685 $string .= $ddp->maybe_colorize($ddp->separator, 'separator')
106             if $total_keys > 0 || $ddp->end_separator;
107              
108             # restore var name back to "var"
109 149         394 $ddp->current_name($original_varname);
110             }
111 69         240 $ddp->outdent;
112 69         188 $string .= $ddp->newline . $ddp->maybe_colorize('}', 'brackets');
113 69         453 return $string . $tied;
114             };
115              
116             #######################################
117             ### Private auxiliary helpers below ###
118             #######################################
119              
120             sub _needs_quote {
121 149     149   291 my ($ddp, $raw_key, $new_key) = @_;
122 149         324 my $quote_keys = $ddp->quote_keys;
123 149         347 my $scalar_quotes = $ddp->scalar_quotes;
124 149 50 33     650 return 0 unless defined $quote_keys && defined $scalar_quotes;;
125 149 50 66     1003 if ($quote_keys eq 'auto'
      66        
126             && $raw_key eq $new_key
127             && $new_key !~ /\s|\r|\n|\t|\f/) {
128 147         447 return 0;
129             }
130 2         8 return 1;
131             }
132              
133             1;