File Coverage

blib/lib/Data/Dumper/Sorted.pm
Criterion Covered Total %
statement 77 95 81.0
branch 39 60 65.0
condition 1 2 50.0
subroutine 15 16 93.7
pod 7 12 58.3
total 139 185 75.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             package Data::Dumper::Sorted;
3             #
4             # recurse2txt routines
5             #
6             # version 1.10, 5-24-13, michael@bizsystems.com
7             #
8             # 10-3-11 updated to bless into calling package
9             # 10-10-11 add SCALAR ref support
10             # 1.06 12-16-12 add hexDumper
11             # 1.07 12-19-12 added wantarray return of data and elements
12             # 1.08 12-20-12 add wantarray to hexDumper
13             # 1.09 5-18-13 add my (data,count)
14             # 1.10 5-24-13 add pod and support for blessed objects
15             # converted to a module
16             #
17             #use strict;
18             #use diagnostics;
19              
20 3     3   2874 use vars qw(@EXPORT_OK $VERSION @ISA);
  3         7  
  3         222  
21 3     3   2543 use overload;
  3         1334  
  3         22  
22             require Exporter;
23              
24             @ISA = qw(Exporter);
25              
26             $VERSION = do { my @r = (q$Revision: 1.12 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
27              
28             @EXPORT_OK = qw(
29             hexDumper
30             hexDumperA
31             hexDumperC
32             Dumper
33             DumperA
34             DumperC
35             );
36              
37             =head1 NAME
38              
39             Data::Dumper::Sorted - Dumper with repeatable signature
40              
41             =head1 SYNOPSIS - similar to Data::Dumper
42              
43             Data::Dumper::Sorted generates a unique signature for hashs
44             by sorting the keys into alphabetic order.
45              
46             Data::Dumper actually does much more than this, however, it
47             does not stringify hash's in a consistent manner. i.e. no SORT
48              
49             The routines below, while not covering recursion loops, non ascii
50             characters, etc.... does produce text that can be eval'd and is
51             consistent with each rendering, version of Perl, and platform.
52              
53             The module routines may be called as functions or methods.
54              
55             use Data::Dumper::Sorted qw(
56             hexDumper
57             hexDumperC
58             hexDumperA
59             Dumper
60             DumperC
61             DumperA
62             };
63              
64             OR as methods
65              
66             require Data::Dumper::Sorted;
67              
68             my $dd = new Data::Dumper::Sorted;
69              
70             A blessed reference is not really needed.
71              
72             my $dd = 'Data::Dumper::Sorted';
73              
74             $countText = $dd->hexDumperC($ref);
75             $evalText = $dd->hexDumper($ref);
76             ($text,$count) = $dd->hexDumperA($ref);
77              
78             $countText = $dd->DumperC($ref);
79             $evalText = $dd->Dumper($ref);
80             ($text,$count) = $dd->DumperA($ref);
81              
82             =item * $dd = new Data::Dumper::Sorted;
83              
84             This method returns a blessed reference that can be used to access the
85             functions in this modules as methods.
86              
87             =cut
88              
89             sub new ($) {
90 1   50 1 1 43 my $class = ref $_[0] || shift || __PACKAGE__;
91 1         4 bless {}, $class;
92             }
93              
94             =item * $countText = hexDumperC($ref);
95              
96             same as:
97             scalar DumperA($ref);
98              
99             It prefixes the dumped text with a COUNT of the
100             nodes in the text instead of a symbol name. This is useful
101             in developing perl test routines.
102              
103             i.e 5 { text....
104              
105             instead of: $Var = { text....
106              
107             =item * $evalText = hexDumper($ref);
108              
109             Same form as Data::Dumper. This method returns a string which
110             can be eval'd to reconstitute the reference.
111              
112             =item * ($text,$count) = hexDumperA($ref);
113              
114             Returns the text of fully numeric data items converted to hex.
115              
116             input: reference
117             return: array context
118             text_for_reference_contents,
119             count_of_data_items
120              
121             scalar context
122             count text_for_reference_contents
123              
124             =cut
125              
126             sub hexDumper {
127 3     3 1 113 my($txt) = &hexDumperA;
128 3         18 return '$Var00 = '. $txt;
129             }
130              
131             sub hexDumperC {
132 3     3 1 298 return scalar &hexDumperA;
133             }
134              
135             sub hexDumperA {
136 12 100   12 1 749 shift if @_ > 1;
137 12         35 my ($data,$count) = DumperA($_[0]);
138 12         94 $data =~ s/([ [])(\d+),/sprintf("%s0x%x,",$1,$2)/ge;
  132         917  
139 12 100       79 return (wantarray) ? ($data,$count) : $count ."\t= ". $data;
140             }
141              
142             =item * $countText = DumperC($ref);
143              
144             same as:
145             scalar DumperA($ref);
146              
147             It prefixes the dumped text with a COUNT of the
148             nodes in the text instead of a symbol name.. This is useful
149             in developing perl test routines.
150              
151             i.e 5 { text....
152              
153             instead of: $Var = { text....
154              
155             =item * $evalText = Dumper($ref);
156              
157             Same form as Data::Dumper. This method returns a string which
158             can be eval'd to reconstitute the reference.
159              
160             =item * ($text,$count) = DumperA($ref);
161              
162             input: reference
163             return: array context
164             text_for_reference_contents,
165             count_of_data_items
166              
167             scalar context
168             count text_for_reference_contents
169              
170             =cut
171              
172             # input: potential reference
173             # return: ref type or '',
174             # blessing if blessed
175              
176             sub __getref {
177 990 100   990   2729 return ('') unless (my $class = ref($_[0]));
178 480 100       1772 if ($class =~ /(HASH|ARRAY|SCALAR|CODE|GLOB)/) {
179 270         819 return ($1,'');
180             }
181 210         552 my($ref) = (overload::StrVal($_[0]) =~ /^(?:.*\=)?([^=]*)\(/);
182 210         1843 return ($ref,$class);
183             }
184              
185             sub Dumper {
186 9     9 1 2500 my($txt) = &DumperA;
187 9         52 return '$Var00 = '. $txt;
188             }
189              
190             sub DumperC {
191 3     3 1 286 return scalar &DumperA;
192             }
193              
194             sub DumperA {
195 30 100   30 1 541 shift if @_ > 1;
196 30 50       65 unless (defined $_[0]) {
197 0 0       0 return ("undef\n",'undef') if wantarray;
198 0         0 return "undef\n";
199             }
200             # my $ref = ref $_[0];
201             # return "not a reference\n" unless $ref;
202             # unless ($ref eq 'HASH' or $ref eq 'ARRAY' or $ref eq 'SCALAR') {
203             # ($ref) = (overload::StrVal($_[0]) =~ /^(?:.*\=)?([^=]*)\(/);
204             # }
205 30         48 my($ref,$class) = &__getref;
206 30 50       69 return "not a reference\n" unless $ref;
207 30         86 my $p = {
208             depth => 0,
209             elements => 0,
210             };
211             # (my $pkg = (caller(0))[3]) =~ s/(.+)::DumperA/$1/;
212             # bless $p,$pkg;
213 30         40 bless $p;
214 30         31 my $data;
215 30 50       61 if ($ref eq 'HASH') {
    0          
216 30         78 $data = $p->hash_recurse($_[0],"\n",$class);
217             }
218             elsif ($ref eq 'ARRAY') {
219 0         0 $data = $p->array_recurse($_[0],'',$class);
220             } else {
221             # return $ref ." unsupported\n";
222 0         0 $data = $p->scalar_recurse($_[0],'',$class);
223             }
224 30         190 $data =~ s/,\n$/;\n/;
225 30 100       180 return ($data,$p->{elements}) if wantarray;
226 6         94 return $p->{elements} ."\t= ". $data;
227             }
228            
229             # input: pointer to scalar, terminator
230             # returns data
231             #
232             sub scalar_recurse {
233 0     0 0 0 my($p,$ptr,$n,$bls) = @_;
234 0 0       0 $n = '' unless $n;
235 0 0       0 my $data = $bls ? 'bless(' : '';
236 0         0 $data .= "\\";
237 0         0 $data .= _dump($p,$$ptr);
238 0 0       0 $data .= " '". $bls ."')," if $bls;
239 0         0 $data .= "\n";
240             }
241              
242             # input: pointer to hash, terminator
243             # returns: data
244             #
245             sub hash_recurse {
246 120     120 0 188 my($p,$ptr,$n,$bls) = @_;
247 120 50       229 $n = '' unless $n;
248 120 100       195 my $data = $bls ? 'bless(' : '';
249 120         159 $data .= "{\n";
250 120         580 foreach my $key (sort keys %$ptr) {
251 750         1201 $data .= "\t'". $key ."'\t=> ";
252 750         1500 $data .= _dump($p,$ptr->{$key},"\n");
253             }
254 120         212 $data .= '},';
255 120 100       251 $data .= " '". $bls ."')," if $bls;
256 120         412 $data .= $n;
257             }
258              
259             # generate a unique signature for a particular array
260             #
261             # input: pointer to array, terminator
262             # returns: data
263             sub array_recurse {
264 150     150 0 206 my($p,$ptr,$n,$bls) = @_;
265 150 100       291 $n = '' unless $n;
266 150 50       229 my $data = $bls ? 'bless(' : '';
267 150         207 $data .= '[';
268 150         230 foreach my $item (@$ptr) {
269 210         353 $data .= _dump($p,$item);
270             }
271 150         215 $data .= "],";
272 150 50       520 $data .= " '". $bls ."')," if $bls;
273 150         519 $data .= "\n";
274             }
275              
276             # input: self, item, append
277             # return: data
278             #
279             sub _dump {
280 960     960   1305 my($p,$item,$n) = @_;
281 960         1361 $p->{elements}++;
282 960 100       1787 $n = '' unless $n;
283 960         1552 my($ref,$class) = __getref($item);
284 960 100       2974 if ($ref eq 'HASH') {
    100          
    50          
    50          
    50          
    100          
    50          
285 90         210 return tabout($p->hash_recurse($item,"\n",$class));
286             }
287             elsif($ref eq 'ARRAY') {
288 150         386 return $p->array_recurse($item,$n,$class);
289             }
290             elsif($ref eq 'SCALAR') {
291             # return q|\$SCALAR,|.$n;
292 0         0 return($p->scalar_recurse($item,$n,$class));
293             }
294 720         889 elsif ($ref eq 'GLOB') {
295 0         0 my $g = *{$item};
  0         0  
296 0         0 return "\\$g" .','.$n;
297             }
298 720         2466 elsif(do {my $g = \$item; ref $g eq 'GLOB'}) {
299 0         0 return "$item" .','.$n;
300             }
301             elsif($ref eq 'CODE') {
302 210         630 return q|sub {'DUMMY'},|.$n;
303             }
304             elsif (defined $item) {
305 510         791 return wrap_data($item) .','.$n;
306             }
307             else {
308 0         0 return 'undef,'.$n;
309             }
310             }
311              
312             sub tabout {
313 90     90 0 527 my @data = split(/\n/,shift);
314 90         159 my $data = shift @data;
315 90         117 $data .= "\n";
316 90         149 foreach(@data) {
317 840         1780 $data .= "\t$_\n";
318             }
319 90         427 $data;
320             }
321              
322             sub wrap_data {
323 510     510 0 592 my $data = shift;
324 510 50       1950 if ($data =~ /^$/) {
    100          
325 0         0 return '';
326             } elsif ($data =~ /\D/) {
327 180         251 $data =~ s/'/\\'/g;
328 180         840 return q|'|. $data .q|'|;
329             }
330 330         1370 $data;
331             }
332              
333             =head1 AUTHOR
334              
335             Michael Robinton,
336              
337             =head1 COPYRIGHT
338              
339             Copyright 2013-2014, Michael Robinton
340              
341             This program is free software; you may redistribute it and/or modify it
342             under the same terms as Perl itself.
343              
344             This program is distributed in the hope that it will be useful,
345             but WITHOUT ANY WARRANTY; without even the implied warranty of
346             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
347              
348             =cut
349              
350             1;