File Coverage

blib/lib/JSON/MergePatch.pm
Criterion Covered Total %
statement 57 57 100.0
branch 28 30 93.3
condition 14 18 77.7
subroutine 10 10 100.0
pod 4 4 100.0
total 113 119 94.9


line stmt bran cond sub pod time code
1             package JSON::MergePatch;
2 3     3   86929 use 5.008001;
  3         10  
3 3     3   13 use strict;
  3         6  
  3         57  
4 3     3   21 use warnings;
  3         4  
  3         125  
5              
6             our $VERSION = "0.02";
7              
8 3     3   2097 use parent 'Exporter';
  3         823  
  3         15  
9 3     3   2342 use JSON::MaybeXS qw/encode_json decode_json/;
  3         14605  
  3         171  
10 3     3   2293 use List::MoreUtils qw/uniq/;
  3         32747  
  3         21  
11              
12             our @EXPORT = qw/json_merge_patch json_merge_diff/;
13              
14              
15             sub patch {
16 52     52 1 11164 my ($class, $target, $patch, $opt) = @_;
17 52 100 100     226 if (defined $target && !$opt->{repeat}) {
18 30         172 $target = decode_json($target);
19             }
20              
21 52 100       128 if (ref $patch eq 'HASH') {
22 28 100       60 unless (ref $target eq 'HASH') {
23 6         15 $target = +{};
24             }
25              
26 28         71 for my $key (keys %$patch) {
27 32 100       69 if (defined $patch->{$key}) {
28 22         88 $target->{$key} = __PACKAGE__->patch($target->{$key}, $patch->{$key}, {repeat => 1});
29             }
30             else {
31 10 100       26 if (exists $target->{$key}) {
32 4         22 delete $target->{$key};
33             }
34             }
35             }
36 28 50       221 return ref $target ? encode_json($target) : $target;
37             }
38              
39 24 100       116 return ref $patch ? encode_json($patch) : $patch;
40             }
41              
42             sub diff {
43 68     68 1 7614 my ($class, $source, $target, $opt) = @_;
44              
45 68         85 my ($decoded_source, $decoded_target);
46 68 100       125 if ($opt->{repeat}) {
47 34         36 $decoded_source = $source;
48 34         35 $decoded_target = $target;
49             } else {
50 34         37 $decoded_source = eval {
51 34         225 decode_json($source);
52             };
53 34 100       69 if ($@) {
54 4         16 return $source;
55             }
56              
57 30         28 $decoded_target = eval {
58 30         91 decode_json($target);
59             };
60 30 100       81 if ($@) {
61 2         7 return $decoded_source;
62             }
63             }
64              
65 62 100       150 if (ref $decoded_source eq 'ARRAY') {
66 8         26 return $decoded_source;
67             }
68              
69 54 100       104 if (ref $decoded_source eq 'HASH') {
70 30 100       54 if (ref $decoded_target eq 'HASH') {
71 26         127 for my $key (uniq (keys %$decoded_target, keys %$decoded_source)) {
72 34         123 $decoded_source->{$key} = __PACKAGE__->diff($decoded_source->{$key}, $decoded_target->{$key}, {repeat => 1});
73              
74 34 50 66     127 if (exists $decoded_target->{$key} && exists $decoded_source->{$key}) {
75 28 100 66     221 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         13 delete $decoded_source->{$key};
80             }
81             }
82             }
83              
84 26         114 return $decoded_source;
85             }
86             else {
87 4         14 return $decoded_source;
88             }
89             }
90              
91 24         53 return $decoded_source;
92             }
93              
94             sub json_merge_patch {
95 15     15 1 44 __PACKAGE__->patch(@_);
96             }
97              
98             sub json_merge_diff {
99 17     17 1 37 __PACKAGE__->diff(@_);
100             }
101              
102              
103             1;
104             __END__