File Coverage

blib/lib/Struct/Diff/MergePatch.pm
Criterion Covered Total %
statement 52 52 100.0
branch 24 24 100.0
condition 3 3 100.0
subroutine 7 7 100.0
pod 2 2 100.0
total 88 88 100.0


line stmt bran cond sub pod time code
1             package Struct::Diff::MergePatch;
2              
3 2     2   70011 use 5.006;
  2         9  
4 2     2   9 use strict;
  2         3  
  2         47  
5 2     2   9 use warnings FATAL => 'all';
  2         2  
  2         52  
6 2     2   428 use parent 'Exporter';
  2         217  
  2         9  
7              
8 2     2   491 use Struct::Diff 0.93;
  2         9684  
  2         748  
9              
10             our @EXPORT_OK = qw(
11             diff
12             patch
13             );
14              
15             =head1 NAME
16              
17             Struct::Diff::MergePatch - JSON Merge Patch
18             (L) for perl structures
19              
20             =begin html
21              
22             Travis CI
23             Coverage Status
24             CPAN version
25              
26             =end html
27              
28             =head1 VERSION
29              
30             Version 0.01
31              
32             =cut
33              
34             our $VERSION = '0.01';
35              
36             =head1 SYNOPSIS
37              
38             use Struct::Diff::MergePatch qw(diff patch);
39              
40             $old = {a => {b => 1,c => [0], d => 5},f => 2};
41             $new = {a => {b => 1,c => [0,1],e => 6},f => 2};
42              
43             $diff = diff($old, $new);
44             # {a => {c => [0,1],d => undef,e => 6}}
45              
46             patch($old, $diff);
47             # $old now equal to $new
48              
49             =head1 EXPORT
50              
51             Nothing is exported by default.
52              
53             =head1 SUBROUTINES
54              
55             =head2 diff
56              
57             Calculate patch for two arguments:
58              
59             $patch = diff($old, $new);
60              
61             Convert L diff to merge patch when single arg passed:
62              
63             $patch = diff(Struct::Diff::diff($old, $new));
64              
65             =cut
66              
67             sub diff($;$) {
68 22     22 1 37283 my $patch;
69 22 100       81 my @stack = (\$patch, @_ == 2 ? Struct::Diff::diff($_[0], $_[1]) : $_[0]);
70              
71 22         2312 while (@stack) {
72 31         57 my ($p, $d) = splice @stack, 0, 2; # subpatch, subdiff
73              
74 31 100       69 if (exists $d->{D}) {
    100          
75 15 100       35 if (ref $d->{D} eq 'ARRAY') {
76 2         5 ${$p} = Struct::Diff::split_diff($d)->{b};
  2         99  
77             } else { # HASH
78 13         16 while (my ($k, $v) = each %{$d->{D}}) {
  34         101  
79 21 100 100     69 if (exists $v->{D} or exists $v->{N}) {
    100          
    100          
80 9         11 push @stack, \${$p}->{$k}, $v;
  9         22  
81             } elsif (exists $v->{A}) {
82 4         6 ${$p}->{$k} = $v->{A};
  4         9  
83             } elsif (exists $v->{R}) {
84 5         6 ${$p}->{$k} = undef;
  5         10  
85             }
86             }
87             }
88             } elsif (exists $d->{N}) {
89 15         17 ${$p} = $d->{N};
  15         42  
90             }
91             }
92              
93 22 100       58 return defined $patch ? $patch : $_[1];
94             }
95              
96             =head2 patch
97              
98             Apply patch.
99              
100             patch($target, $patch);
101              
102             =cut
103              
104             sub patch($$) {
105 23     23 1 23132 my @stack = (\$_[0], $_[1]); # ref to alias - to be able to change passed scalar
106              
107 23         52 while (@stack) {
108 30         50 my ($t, $p) = splice @stack, 0, 2; # subtarget, subpatch
109              
110 30 100       58 if (ref $p eq 'HASH') {
111 19 100       22 ${$t} = {} unless (ref ${$t} eq 'HASH');
  5         7  
  19         38  
112              
113 19         25 while (my ($k, $v) = each %{$p}) {
  40         104  
114 21 100       42 if (not defined $v) {
    100          
115 6         8 delete ${$t}->{$k};
  6         10  
116             } elsif (ref $v) {
117 7         9 push @stack, \${$t}->{$k}, $v;
  7         15  
118             } else {
119 8         8 ${$t}->{$k} = $v;
  8         17  
120             }
121             }
122             } else {
123 11         24 ${$t} = $p;
  11         30  
124             }
125             }
126             }
127              
128             =head1 AUTHOR
129              
130             Michael Samoglyadov, C<< >>
131              
132             =head1 BUGS
133              
134             Please report any bugs or feature requests to
135             C, or through the web interface at
136             L. I
137             will be notified, and then you'll automatically be notified of progress on
138             your bug as I make changes.
139              
140             =head1 SUPPORT
141              
142             You can find documentation for this module with the perldoc command.
143              
144             perldoc Struct::Diff::MergePatch
145              
146             You can also look for information at:
147              
148             =over 4
149              
150             =item * RT: CPAN's request tracker (report bugs here)
151              
152             L
153              
154             =item * AnnoCPAN: Annotated CPAN documentation
155              
156             L
157              
158             =item * CPAN Ratings
159              
160             L
161              
162             =item * Search CPAN
163              
164             L
165              
166             =back
167              
168             =head1 SEE ALSO
169              
170             L, L,
171             L
172              
173             =head1 LICENSE AND COPYRIGHT
174              
175             Copyright 2017 Michael Samoglyadov.
176              
177             This program is free software; you can redistribute it and/or modify it under
178             the terms of either: the GNU General Public License as published by the Free
179             Software Foundation; or the Artistic License.
180              
181             See L for more information.
182              
183             =cut
184              
185             1; # End of Struct::Diff::MergePatch