File Coverage

blib/lib/JSON/MergePatch.pm
Criterion Covered Total %
statement 58 58 100.0
branch 29 30 96.6
condition 14 18 77.7
subroutine 10 10 100.0
pod 4 4 100.0
total 115 120 95.8


line stmt bran cond sub pod time code
1             package JSON::MergePatch;
2 3     3   57947 use 5.008001;
  3         10  
  3         113  
3 3     3   16 use strict;
  3         4  
  3         93  
4 3     3   15 use warnings;
  3         16  
  3         150  
5              
6             our $VERSION = "0.01";
7              
8 3     3   1455 use parent 'Exporter';
  3         903  
  3         15  
9 3     3   1291 use JSON qw/encode_json decode_json/;
  3         17658  
  3         17  
10 3     3   2115 use List::MoreUtils qw/uniq/;
  3         26738  
  3         37  
11              
12             our @EXPORT = qw/json_merge_patch json_merge_diff/;
13              
14              
15             sub patch {
16 52     52 1 8777 my ($class, $target, $patch, $opt) = @_;
17 52 100 100     206 if (defined $target && !$opt->{repeat}) {
18 30         135 $target = decode_json($target);
19             }
20              
21 52 100       113 if (ref $patch eq 'HASH') {
22 28 100       61 unless (ref $target eq 'HASH') {
23 6         9 $target = +{};
24             }
25              
26 28         74 for my $key (keys $patch) {
27 32 100       57 if (defined $patch->{$key}) {
28 22         77 $target->{$key} = __PACKAGE__->patch($target->{$key}, $patch->{$key}, {repeat => 1});
29             }
30             else {
31 10 100       23 if (exists $target->{$key}) {
32 4         9 delete $target->{$key};
33             }
34             }
35             }
36 28 50       207 return ref $target ? encode_json($target) : $target;
37             }
38              
39 24 100       118 return ref $patch ? encode_json($patch) : $patch;
40             }
41              
42             sub diff {
43 68     68 1 7370 my ($class, $source, $target, $opt) = @_;
44              
45 68         61 my ($decoded_source, $decoded_target);
46 68 100       119 if ($opt->{repeat}) {
47 34         34 $decoded_source = $source;
48 34         31 $decoded_target = $target;
49             } else {
50 34         38 $decoded_source = eval {
51 34         187 decode_json($source);
52             };
53 34 100       77 if ($@) {
54 4         13 return $source;
55             }
56              
57 30         23 $decoded_target = eval {
58 30         85 decode_json($target);
59             };
60 30 100       57 if ($@) {
61 2         9 return $decoded_source;
62             }
63             }
64              
65 62 100       108 if (ref $decoded_source eq 'ARRAY') {
66 8         46 return $decoded_source;
67             }
68              
69 54 100       80 if (ref $decoded_source eq 'HASH') {
70 30 100       43 if (ref $decoded_target eq 'HASH') {
71 26         130 for my $key (uniq (keys $decoded_target, keys $decoded_source)) {
72 34         120 $decoded_source->{$key} = __PACKAGE__->diff($decoded_source->{$key}, $decoded_target->{$key}, {repeat => 1});
73              
74 34 100 66     178 if (exists $decoded_target->{$key} && exists $decoded_source->{$key}) {
75 28 100 66     217 if (
      66        
      100        
      66        
76             (!defined $decoded_target->{$key} && !defined $decoded_source->{$key}) ||
77             (defined $decoded_target->{$key} && defined $decoded_source->{$key} && $decoded_target->{$key} eq $decoded_source->{$key})
78             ) {
79 6         14 delete $decoded_source->{$key};
80             }
81             }
82             }
83              
84 26         106 return $decoded_source;
85             }
86             else {
87 4         12 return $decoded_source;
88             }
89             }
90              
91 24         49 return $decoded_source;
92             }
93              
94             sub json_merge_patch {
95 15     15 1 42 __PACKAGE__->patch(@_);
96             }
97              
98             sub json_merge_diff {
99 17     17 1 47 __PACKAGE__->diff(@_);
100             }
101              
102              
103             1;
104             __END__