File Coverage

recurse2txt
Criterion Covered Total %
statement 40 90 44.4
branch 21 58 36.2
condition 0 3 0.0
subroutine 7 13 53.8
pod n/a
total 68 164 41.4


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #
3             # recurse2txt routines
4             #
5             # version 1.10, 5-24-13, michael@bizsystems.com
6             #
7             # 10-3-11 updated to bless into calling package
8             # 10-10-11 add SCALAR ref support
9             # 1.06 12-16-12 add hexDumper
10             # 1.07 12-19-12 added wantarray return of data and elements
11             # 1.08 12-20-12 add wantarray to hexDumper
12             # 1.09 5-18-13 add my (data,count)
13             # 1.10 5-24-13 add pod and support for blessed objects
14             #
15             #use strict;
16             #use diagnostics;
17              
18 1     1   620 use overload;
  1         2  
  1         8  
19              
20             =head1 $ref to text - similar to Data::Dumper
21              
22             recurse2txt generates a unique signature for a particular hash
23              
24             Data::Dumper actually does much more than this, however, it
25             does not stringify hash's in a consistent manner. i.e. no SORT
26              
27             The routines below, while not covering recursion loops, non ascii
28             characters, etc.... does produce text that can be eval'd and is
29             consistent with each rendering.
30              
31             =item * hexDumper($ref);
32              
33             same as:
34             scalar hexDumperA(ref);
35              
36             =item * hexDumperA($ref);
37              
38             Returns the text of the data items converted to hex.
39              
40             input: reference
41             return: array context
42             text_for_reference_contents,
43             count_of_data_items
44              
45             scalar context
46             count text_for_reference_contents
47              
48             =cut
49              
50             #
51             sub hexDumper {
52 0     0   0 return scalar &hexDumperA;
53             }
54              
55             sub hexDumperA {
56 0 0   0   0 if (wantarray) {
57 0         0 my ($data,$count) = Dumper($_[0]);
58 0         0 $data =~ s/(\b\d+)/sprintf("0x%x",$1)/ge;
  0         0  
59 0         0 return ($data,$count);
60             }
61 0         0 (my $x = Dumper($_[0])) =~ s/(\b\d+)/sprintf("0x%x",$1)/ge;
  0         0  
62 0         0 $x;
63             }
64              
65             =item * Dumper($ref);
66              
67             same as:
68             scalar DumperA($ref);
69              
70             =item * DumperA($ref);
71              
72             input: reference
73             return: array context
74             text_for_reference_contents,
75             count_of_data_items
76              
77             scalar context
78             count text_for_reference_contents
79              
80             =cut
81              
82             # input: potential reference
83             # return: ref type or '',
84             # blessing if blessed
85              
86             sub __getref {
87 4329 100   4329   11656 return ('') unless (my $class = ref($_[0]));
88 6 50       41 if ($class =~ /(HASH|ARRAY|SCALAR|CODE|GLOB)/) {
89 6         25 return ($1,'');
90             }
91 0         0 my($ref) = (overload::StrVal($_[0]) =~ /^(?:.*\=)?([^=]*)\(/);
92 0         0 return ($ref,$class);
93             }
94              
95             sub Dumper {
96 6     6   29 return scalar &DumperA;
97             }
98              
99             sub DumperA {
100 6 50   6   16 unless (defined $_[0]) {
101 0 0       0 return ("undef\n",'undef') if wantarray;
102 0         0 return "undef\n";
103             }
104             # my $ref = ref $_[0];
105             # return "not a reference\n" unless $ref;
106             # unless ($ref eq 'HASH' or $ref eq 'ARRAY' or $ref eq 'SCALAR') {
107             # ($ref) = (overload::StrVal($_[0]) =~ /^(?:.*\=)?([^=]*)\(/);
108             # }
109 6         13 my($ref,$class) = &__getref;
110 6 50       15 return "not a reference\n" unless $ref;
111 6         20 my $p = {
112             depth => 0,
113             elements => 0,
114             };
115 6         55 (my $pkg = (caller(0))[3]) =~ s/(.+)::DumperA/$1/;
116 6         43 bless $p,$pkg;
117 6         7 my $data;
118 6 50       19 if ($ref eq 'HASH') {
    50          
119 0         0 $data = $p->hash_recurse($_[0],"\n",$class);
120             }
121             elsif ($ref eq 'ARRAY') {
122 6         22 $data = $p->array_recurse($_[0],'',$class);
123             } else {
124             # return $ref ." unsupported\n";
125 0         0 $data = $p->scalar_recurse($_[0],'',$class);
126             }
127 6         153 $data =~ s/,\n$/;\n/;
128 6 50       14 return ($data,$p->{elements}) if wantarray;
129 6         165 return $p->{elements} ."\t= ". $data;
130             }
131            
132             # input: pointer to scalar, terminator
133             # returns data
134             #
135             sub scalar_recurse {
136 0     0   0 my($p,$ptr,$n,$bls) = @_;
137 0 0       0 $n = '' unless $n;
138 0 0       0 my $data = $bls ? 'bless ' : '';
139 0         0 $data .= "\\";
140 0         0 $data .= _dump($p,$$ptr);
141 0 0       0 $data .= " '". $bls ."'," if $bls;
142 0         0 $data .= "\n";
143             }
144              
145             # input: pointer to hash, terminator
146             # returns: data
147             #
148             sub hash_recurse {
149 0     0   0 my($p,$ptr,$n,$bls) = @_;
150 0 0       0 $n = '' unless $n;
151 0 0       0 my $data = $bls ? 'bless ' : '';
152 0         0 $data .= "{\n";
153 0         0 foreach my $key (sort keys %$ptr) {
154 0         0 $data .= "\t'". $key ."'\t=> ";
155 0         0 $data .= _dump($p,$ptr->{$key},"\n");
156             }
157 0         0 $data .= '},';
158 0 0       0 $data .= " '". $bls ."'," if $bls;
159 0         0 $data .= $n;
160             }
161              
162             # generate a unique signature for a particular array
163             #
164             # input: pointer to array, terminator
165             # returns: data
166             sub array_recurse {
167 6     6   7 my($p,$ptr,$n,$bls) = @_;
168 6 50       14 $n = '' unless $n;
169 6 50       14 my $data = $bls ? 'bless ' : '';
170 6         8 $data .= '[';
171 6         13 foreach my $item (@$ptr) {
172 4323         7628 $data .= _dump($p,$item);
173             }
174 6         7 $data .= "],";
175 6 50       14 $data .= " '". $bls ."'," if $bls;
176 6         113 $data .= "\n";
177             }
178              
179             # input: self, item, append
180             # return: data
181             #
182             sub _dump {
183 4323     4323   5891 my($p,$item,$n) = @_;
184 4323         5274 $p->{elements}++;
185 4323 50       8263 $n = '' unless $n;
186 4323         6881 my($ref,$class) = __getref($item);
187 4323 50       13290 if ($ref eq 'HASH') {
    50          
    50          
    50          
    50          
    50          
    50          
188 0         0 return tabout($p->hash_recurse($item,"\n",$class));
189             }
190             elsif($ref eq 'ARRAY') {
191 0         0 return $p->array_recurse($item,$n,$class);
192             }
193             elsif($ref eq 'SCALAR') {
194             # return q|\$SCALAR,|.$n;
195 0         0 return($p->scalar_recurse($item,$n,$class));
196             }
197 4323         5239 elsif ($ref eq 'GLOB') {
198 0         0 my $g = *{$item};
  0         0  
199 0         0 return "\\$g" .','.$n;
200             }
201 4323         14563 elsif(do {my $g = \$item; ref $g eq 'GLOB'}) {
202 0         0 return "$item" .','.$n;
203             }
204             elsif($ref eq 'CODE') {
205 0         0 return q|sub {'DUMMY'},|.$n;
206             }
207             elsif (defined $item) {
208 4323         7386 return wrap_data($item) .','.$n;
209             }
210             else {
211 0         0 return 'undef,'.$n;
212             }
213             }
214              
215             sub tabout {
216 0     0   0 my @data = split(/\n/,shift);
217 0         0 my $data = shift @data;
218 0         0 $data .= "\n";
219 0         0 foreach(@data) {
220 0         0 $data .= "\t$_\n";
221             }
222 0         0 $data;
223             }
224              
225             sub wrap_data {
226 4323     4323   4848 my $data = shift;
227 4323 50       15622 if ($data =~ /^$/) {
    50          
228 0         0 return '';
229             } elsif ($data =~ /\D/) {
230 4323         5522 $data =~ s/'/\\'/g;
231 4323         24577 return q|'|. $data .q|'|;
232             }
233 0           $data;
234             }
235              
236             sub xx {
237 0 0 0 0     return ($data =~ /\D/ || $data =~ /^$/)
238             ? q|'|. $data .q|'|
239             : $data;
240             }
241              
242             1;