File Coverage

blib/lib/Struct/Compare.pm
Criterion Covered Total %
statement 54 56 96.4
branch 28 34 82.3
condition 4 7 57.1
subroutine 7 7 100.0
pod 1 1 100.0
total 94 105 89.5


line stmt bran cond sub pod time code
1             package Struct::Compare;
2              
3             =head1 NAME
4              
5             Struct::Compare - Recursive diff for perl structures.
6              
7             =head1 SYNOPSIS
8              
9             use Struct::Compare;
10             my $is_different = compare($ref1, $ref2);
11              
12             =head1 DESCRIPTION
13              
14             Compares two values of any type and structure and returns true if they
15             are the same. It does a deep comparison of the structures, so a hash
16             of a hash of a whatever will be compared correctly.
17              
18             This is especially useful for writing unit tests for your modules!
19              
20             =head1 PUBLIC FUNCTIONS
21              
22             =over 4
23              
24             =cut
25              
26 1     1   734 use strict;
  1         2  
  1         47  
27             require Exporter;
28 1     1   5 use vars qw($VERSION @ISA @EXPORT);
  1         2  
  1         81  
29 1     1   5 use Carp qw(croak);
  1         5  
  1         101  
30              
31             @ISA = qw(Exporter);
32             @EXPORT = qw(compare);
33              
34             $VERSION = '1.0.1';
35              
36             # TODO: document
37              
38 1     1   5 use constant FALSE=>0;
  1         2  
  1         87  
39 1     1   5 use constant TRUE =>1;
  1         2  
  1         39  
40 1     1   5 use constant DEBUG=>0;
  1         1  
  1         581  
41              
42             =item * $bool = compare($var1, $var2)
43              
44             Recursively compares $var1 to $var2, returning false if either
45             structure is different than the other at any point. If both are
46             undefined, it returns true as well, because that is considered equal.
47              
48             =cut
49              
50             sub compare {
51 60     60 1 8352 my $x = shift;
52 60         60 my $y = shift;
53              
54 60 50       223 if (@_) {
55 0         0 croak "Too many items sent to compare";
56             }
57              
58 60 100 75     281 return FALSE if defined $x xor defined $y;
59 58 0 33     106 return TRUE if ! defined $x and ! defined $y;
60              
61 58 100       124 my $a = ref $x ? $x : \$x;
62 58 100       100 my $b = ref $y ? $y : \$y;
63              
64 58         49 print "\$a is a ", ref $a, "\n" if DEBUG;
65 58         56 print "\$b is a ", ref $b, "\n" if DEBUG;
66              
67 58 100       139 return FALSE unless ref $a eq ref $b;
68              
69 57 100       109 if (ref $a eq 'SCALAR') {
70 25         30 print "a = $$a, b = $$b\n" if DEBUG;
71 25         132 return $$a eq $$b;
72             }
73              
74 32 100       67 if (ref $a eq 'HASH') {
75 18         19 my @keys = keys %{$a};
  18         55  
76 18         27 my $max = scalar(@keys);
77 18 100       19 return FALSE if $max != scalar(keys %{$b});
  18         66  
78 17 100       37 return TRUE if $max == 0;
79              
80             # first just look to see if there are any keys not in the other;
81 16         17 my $found = 0;
82 16         20 foreach my $key (@keys) {
83 26 50       65 $found++ if exists $b->{$key};
84             }
85              
86 16 50       60 return FALSE if $found != $max;
87              
88             # now compare the values
89 16         18 foreach my $key (@keys) {
90             # WARN: recursion may get really deep.
91 23 100       88 return FALSE unless compare($a->{$key}, $b->{$key});
92             }
93              
94 9         35 return TRUE;
95             }
96              
97 14 50       35 if (ref $a eq 'ARRAY') {
98 14         17 my $max = scalar(@{$a});
  14         21  
99 14 100       20 return FALSE if $max != scalar(@{$b});
  14         57  
100 11 100       46 return TRUE if $max == 0;
101              
102 7         18 for (my $i = 0; $i < $max; ++$i) {
103             # WARN: recursion may get really deep.
104 15 100       156 return FALSE unless compare($a->[$i], $b->[$i]);
105             }
106              
107 5         20 return TRUE;
108             }
109              
110             # FIX: doesn't deal with non-basic types... see if you can fake it.
111              
112 0           return FALSE;
113             }
114              
115             1;
116              
117             __END__