diff-lcs 1.3 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/Contributing.md +86 -48
- data/History.md +370 -159
- data/License.md +6 -4
- data/Manifest.txt +23 -1
- data/README.rdoc +10 -10
- data/Rakefile +109 -36
- data/bin/htmldiff +9 -6
- data/bin/ldiff +4 -1
- data/lib/diff/lcs/array.rb +2 -2
- data/lib/diff/lcs/backports.rb +9 -0
- data/lib/diff/lcs/block.rb +5 -5
- data/lib/diff/lcs/callbacks.rb +22 -17
- data/lib/diff/lcs/change.rb +42 -49
- data/lib/diff/lcs/htmldiff.rb +21 -12
- data/lib/diff/lcs/hunk.rb +160 -73
- data/lib/diff/lcs/internals.rb +57 -56
- data/lib/diff/lcs/ldiff.rb +63 -57
- data/lib/diff/lcs/string.rb +1 -1
- data/lib/diff/lcs.rb +226 -210
- data/lib/diff-lcs.rb +2 -2
- data/spec/change_spec.rb +58 -34
- data/spec/diff_spec.rb +13 -9
- data/spec/fixtures/aX +1 -0
- data/spec/fixtures/bXaX +1 -0
- data/spec/fixtures/ldiff/output.diff +4 -0
- data/spec/fixtures/ldiff/output.diff-c +7 -0
- data/spec/fixtures/ldiff/output.diff-e +3 -0
- data/spec/fixtures/ldiff/output.diff-f +3 -0
- data/spec/fixtures/ldiff/output.diff-u +5 -0
- data/spec/fixtures/ldiff/output.diff.chef +4 -0
- data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
- data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
- data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
- data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
- data/spec/fixtures/new-chef +4 -0
- data/spec/fixtures/new-chef2 +17 -0
- data/spec/fixtures/old-chef +4 -0
- data/spec/fixtures/old-chef2 +14 -0
- data/spec/hunk_spec.rb +48 -37
- data/spec/issues_spec.rb +132 -21
- data/spec/lcs_spec.rb +3 -3
- data/spec/ldiff_spec.rb +74 -32
- data/spec/patch_spec.rb +14 -20
- data/spec/sdiff_spec.rb +83 -81
- data/spec/spec_helper.rb +146 -91
- data/spec/traverse_balanced_spec.rb +138 -136
- data/spec/traverse_sequences_spec.rb +7 -9
- metadata +76 -48
- data/autotest/discover.rb +0 -1
data/lib/diff/lcs.rb
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Diff; end unless defined? Diff
|
|
4
|
+
|
|
4
5
|
# == How Diff Works (by Mark-Jason Dominus)
|
|
5
6
|
#
|
|
6
|
-
# I once read an article written by the authors of +diff+; they said that
|
|
7
|
-
#
|
|
8
|
-
# one.
|
|
7
|
+
# I once read an article written by the authors of +diff+; they said that they
|
|
8
|
+
# hard worked very hard on the algorithm until they found the right one.
|
|
9
9
|
#
|
|
10
|
-
# I think what they ended up using (and I hope someone will correct me,
|
|
11
|
-
#
|
|
12
|
-
#
|
|
10
|
+
# I think what they ended up using (and I hope someone will correct me, because
|
|
11
|
+
# I am not very confident about this) was the `longest common subsequence'
|
|
12
|
+
# method. In the LCS problem, you have two sequences of items:
|
|
13
13
|
#
|
|
14
14
|
# a b c d f g h j q z
|
|
15
15
|
# a b c d e f g i j k r x y z
|
|
16
16
|
#
|
|
17
17
|
# and you want to find the longest sequence of items that is present in both
|
|
18
18
|
# original sequences in the same order. That is, you want to find a new
|
|
19
|
-
# sequence *S* which can be obtained from the first sequence by deleting
|
|
20
|
-
#
|
|
21
|
-
#
|
|
19
|
+
# sequence *S* which can be obtained from the first sequence by deleting some
|
|
20
|
+
# items, and from the second sequence by deleting other items. You also want
|
|
21
|
+
# *S* to be as long as possible. In this case *S* is:
|
|
22
22
|
#
|
|
23
23
|
# a b c d f g j z
|
|
24
24
|
#
|
|
@@ -30,9 +30,9 @@ module Diff; end unless defined? Diff
|
|
|
30
30
|
# This module solves the LCS problem. It also includes a canned function to
|
|
31
31
|
# generate +diff+-like output.
|
|
32
32
|
#
|
|
33
|
-
# It might seem from the example above that the LCS of two sequences is
|
|
34
|
-
#
|
|
35
|
-
#
|
|
33
|
+
# It might seem from the example above that the LCS of two sequences is always
|
|
34
|
+
# pretty obvious, but that's not always the case, especially when the two
|
|
35
|
+
# sequences have many repeated elements. For example, consider
|
|
36
36
|
#
|
|
37
37
|
# a x b y c z p d q
|
|
38
38
|
# a b c a x b y c z
|
|
@@ -43,29 +43,35 @@ module Diff; end unless defined? Diff
|
|
|
43
43
|
# a x b y c z p d q
|
|
44
44
|
# a b c a b y c z
|
|
45
45
|
#
|
|
46
|
-
# This finds the common subsequence +a b c z+. But actually, the LCS is +a x
|
|
47
|
-
#
|
|
46
|
+
# This finds the common subsequence +a b c z+. But actually, the LCS is +a x b
|
|
47
|
+
# y c z+:
|
|
48
48
|
#
|
|
49
49
|
# a x b y c z p d q
|
|
50
50
|
# a b c a x b y c z
|
|
51
51
|
module Diff::LCS
|
|
52
|
-
VERSION =
|
|
52
|
+
VERSION = "1.5.1"
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
require
|
|
56
|
-
require
|
|
55
|
+
require "diff/lcs/callbacks"
|
|
56
|
+
require "diff/lcs/internals"
|
|
57
57
|
|
|
58
58
|
module Diff::LCS
|
|
59
59
|
# Returns an Array containing the longest common subsequence(s) between
|
|
60
|
-
# +self+ and +other+. See Diff::LCS#
|
|
60
|
+
# +self+ and +other+. See Diff::LCS#lcs.
|
|
61
61
|
#
|
|
62
62
|
# lcs = seq1.lcs(seq2)
|
|
63
|
-
|
|
63
|
+
#
|
|
64
|
+
# A note when using objects: Diff::LCS only works properly when each object
|
|
65
|
+
# can be used as a key in a Hash, which typically means that the objects must
|
|
66
|
+
# implement Object#eql? in a way that two identical values compare
|
|
67
|
+
# identically for key purposes. That is:
|
|
68
|
+
#
|
|
69
|
+
# O.new('a').eql?(O.new('a')) == true
|
|
70
|
+
def lcs(other, &block) # :yields: self[i] if there are matched subsequences
|
|
64
71
|
Diff::LCS.lcs(self, other, &block)
|
|
65
72
|
end
|
|
66
73
|
|
|
67
|
-
# Returns the difference set between +self+ and +other+. See
|
|
68
|
-
# Diff::LCS#diff.
|
|
74
|
+
# Returns the difference set between +self+ and +other+. See Diff::LCS#diff.
|
|
69
75
|
def diff(other, callbacks = nil, &block)
|
|
70
76
|
Diff::LCS.diff(self, other, callbacks, &block)
|
|
71
77
|
end
|
|
@@ -79,29 +85,27 @@ module Diff::LCS
|
|
|
79
85
|
# Traverses the discovered longest common subsequences between +self+ and
|
|
80
86
|
# +other+. See Diff::LCS#traverse_sequences.
|
|
81
87
|
def traverse_sequences(other, callbacks = nil, &block)
|
|
82
|
-
traverse_sequences(self, other, callbacks ||
|
|
83
|
-
Diff::LCS.YieldingCallbacks, &block)
|
|
88
|
+
Diff::LCS.traverse_sequences(self, other, callbacks || Diff::LCS::SequenceCallbacks, &block)
|
|
84
89
|
end
|
|
85
90
|
|
|
86
91
|
# Traverses the discovered longest common subsequences between +self+ and
|
|
87
92
|
# +other+ using the alternate, balanced algorithm. See
|
|
88
93
|
# Diff::LCS#traverse_balanced.
|
|
89
94
|
def traverse_balanced(other, callbacks = nil, &block)
|
|
90
|
-
traverse_balanced(self, other, callbacks ||
|
|
91
|
-
Diff::LCS.YieldingCallbacks, &block)
|
|
95
|
+
Diff::LCS.traverse_balanced(self, other, callbacks || Diff::LCS::BalancedCallbacks, &block)
|
|
92
96
|
end
|
|
93
97
|
|
|
94
|
-
# Attempts to patch +self+ with the provided +patchset+. A new sequence
|
|
95
|
-
#
|
|
96
|
-
#
|
|
98
|
+
# Attempts to patch +self+ with the provided +patchset+. A new sequence based
|
|
99
|
+
# on +self+ and the +patchset+ will be created. See Diff::LCS#patch. Attempts
|
|
100
|
+
# to autodiscover the direction of the patch.
|
|
97
101
|
def patch(patchset)
|
|
98
102
|
Diff::LCS.patch(self, patchset)
|
|
99
103
|
end
|
|
100
104
|
alias_method :unpatch, :patch
|
|
101
105
|
|
|
102
|
-
# Attempts to patch +self+ with the provided +patchset+. A new sequence
|
|
103
|
-
#
|
|
104
|
-
#
|
|
106
|
+
# Attempts to patch +self+ with the provided +patchset+. A new sequence based
|
|
107
|
+
# on +self+ and the +patchset+ will be created. See Diff::LCS#patch. Does no
|
|
108
|
+
# patch direction autodiscovery.
|
|
105
109
|
def patch!(patchset)
|
|
106
110
|
Diff::LCS.patch!(self, patchset)
|
|
107
111
|
end
|
|
@@ -114,8 +118,8 @@ module Diff::LCS
|
|
|
114
118
|
end
|
|
115
119
|
|
|
116
120
|
# Attempts to patch +self+ with the provided +patchset+, using #patch!. If
|
|
117
|
-
# the sequence this is used on supports #replace, the value of +self+ will
|
|
118
|
-
#
|
|
121
|
+
# the sequence this is used on supports #replace, the value of +self+ will be
|
|
122
|
+
# replaced. See Diff::LCS#patch. Does no patch direction autodiscovery.
|
|
119
123
|
def patch_me(patchset)
|
|
120
124
|
if respond_to? :replace
|
|
121
125
|
replace(patch!(patchset))
|
|
@@ -124,10 +128,9 @@ module Diff::LCS
|
|
|
124
128
|
end
|
|
125
129
|
end
|
|
126
130
|
|
|
127
|
-
# Attempts to unpatch +self+ with the provided +patchset+, using
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
# autodiscovery.
|
|
131
|
+
# Attempts to unpatch +self+ with the provided +patchset+, using #unpatch!.
|
|
132
|
+
# If the sequence this is used on supports #replace, the value of +self+ will
|
|
133
|
+
# be replaced. See Diff::LCS#unpatch. Does no patch direction autodiscovery.
|
|
131
134
|
def unpatch_me(patchset)
|
|
132
135
|
if respond_to? :replace
|
|
133
136
|
replace(unpatch!(patchset))
|
|
@@ -138,33 +141,32 @@ module Diff::LCS
|
|
|
138
141
|
end
|
|
139
142
|
|
|
140
143
|
class << Diff::LCS
|
|
141
|
-
def lcs(seq1, seq2, &block)
|
|
144
|
+
def lcs(seq1, seq2, &block) # :yields: seq1[i] for each matched
|
|
142
145
|
matches = Diff::LCS::Internals.lcs(seq1, seq2)
|
|
143
146
|
ret = []
|
|
144
|
-
string = seq1.
|
|
145
|
-
matches.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
string = seq1.is_a? String
|
|
148
|
+
matches.each_index do |i|
|
|
149
|
+
next if matches[i].nil?
|
|
150
|
+
|
|
151
|
+
v = string ? seq1[i, 1] : seq1[i]
|
|
152
|
+
v = block[v] if block
|
|
153
|
+
ret << v
|
|
151
154
|
end
|
|
152
155
|
ret
|
|
153
156
|
end
|
|
154
157
|
alias_method :LCS, :lcs
|
|
155
158
|
|
|
156
159
|
# #diff computes the smallest set of additions and deletions necessary to
|
|
157
|
-
# turn the first sequence into the second, and returns a description of
|
|
158
|
-
#
|
|
160
|
+
# turn the first sequence into the second, and returns a description of these
|
|
161
|
+
# changes.
|
|
159
162
|
#
|
|
160
163
|
# See Diff::LCS::DiffCallbacks for the default behaviour. An alternate
|
|
161
164
|
# behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If a
|
|
162
165
|
# Class argument is provided for +callbacks+, #diff will attempt to
|
|
163
|
-
# initialise it. If the +callbacks+ object (possibly initialised) responds
|
|
164
|
-
#
|
|
165
|
-
def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes
|
|
166
|
-
diff_traversal(:diff, seq1, seq2, callbacks || Diff::LCS::DiffCallbacks,
|
|
167
|
-
&block)
|
|
166
|
+
# initialise it. If the +callbacks+ object (possibly initialised) responds to
|
|
167
|
+
# #finish, it will be called.
|
|
168
|
+
def diff(seq1, seq2, callbacks = nil, &block) # :yields: diff changes
|
|
169
|
+
diff_traversal(:diff, seq1, seq2, callbacks || Diff::LCS::DiffCallbacks, &block)
|
|
168
170
|
end
|
|
169
171
|
|
|
170
172
|
# #sdiff computes all necessary components to show two sequences and their
|
|
@@ -179,18 +181,31 @@ class << Diff::LCS
|
|
|
179
181
|
# See Diff::LCS::SDiffCallbacks for the default behaviour. An alternate
|
|
180
182
|
# behaviour may be implemented with Diff::LCS::ContextDiffCallbacks. If a
|
|
181
183
|
# Class argument is provided for +callbacks+, #diff will attempt to
|
|
182
|
-
# initialise it. If the +callbacks+ object (possibly initialised) responds
|
|
183
|
-
#
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
# initialise it. If the +callbacks+ object (possibly initialised) responds to
|
|
185
|
+
# #finish, it will be called.
|
|
186
|
+
#
|
|
187
|
+
# Each element of a returned array is a Diff::LCS::ContextChange object,
|
|
188
|
+
# which can be implicitly converted to an array.
|
|
189
|
+
#
|
|
190
|
+
# Diff::LCS.sdiff(a, b).each do |action, (old_pos, old_element), (new_pos, new_element)|
|
|
191
|
+
# case action
|
|
192
|
+
# when '!'
|
|
193
|
+
# # replace
|
|
194
|
+
# when '-'
|
|
195
|
+
# # delete
|
|
196
|
+
# when '+'
|
|
197
|
+
# # insert
|
|
198
|
+
# end
|
|
199
|
+
# end
|
|
200
|
+
def sdiff(seq1, seq2, callbacks = nil, &block) # :yields: diff changes
|
|
201
|
+
diff_traversal(:sdiff, seq1, seq2, callbacks || Diff::LCS::SDiffCallbacks, &block)
|
|
187
202
|
end
|
|
188
203
|
|
|
189
|
-
# #traverse_sequences is the most general facility provided by this
|
|
190
|
-
#
|
|
204
|
+
# #traverse_sequences is the most general facility provided by this module;
|
|
205
|
+
# #diff and #lcs are implemented as calls to it.
|
|
191
206
|
#
|
|
192
|
-
# The arguments to #traverse_sequences are the two sequences to traverse,
|
|
193
|
-
#
|
|
207
|
+
# The arguments to #traverse_sequences are the two sequences to traverse, and
|
|
208
|
+
# a callback object, like this:
|
|
194
209
|
#
|
|
195
210
|
# traverse_sequences(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new)
|
|
196
211
|
#
|
|
@@ -218,106 +233,106 @@ class << Diff::LCS
|
|
|
218
233
|
# ^
|
|
219
234
|
# b---+
|
|
220
235
|
#
|
|
221
|
-
# If there are two arrows (+a+ and +b+) pointing to elements of sequences
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
#
|
|
227
|
-
#
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
# that
|
|
236
|
-
#
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
-
#
|
|
240
|
-
#
|
|
241
|
-
#
|
|
242
|
-
# The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>,
|
|
243
|
-
#
|
|
244
|
-
#
|
|
245
|
-
#
|
|
246
|
-
#
|
|
236
|
+
# If there are two arrows (+a+ and +b+) pointing to elements of sequences +A+
|
|
237
|
+
# and +B+, the arrows will initially point to the first elements of their
|
|
238
|
+
# respective sequences. #traverse_sequences will advance the arrows through
|
|
239
|
+
# the sequences one element at a time, calling a method on the user-specified
|
|
240
|
+
# callback object before each advance. It will advance the arrows in such a
|
|
241
|
+
# way that if there are elements <tt>A[i]</tt> and <tt>B[j]</tt> which are
|
|
242
|
+
# both equal and part of the longest common subsequence, there will be some
|
|
243
|
+
# moment during the execution of #traverse_sequences when arrow +a+ is
|
|
244
|
+
# pointing to <tt>A[i]</tt> and arrow +b+ is pointing to <tt>B[j]</tt>. When
|
|
245
|
+
# this happens, #traverse_sequences will call <tt>callbacks#match</tt> and
|
|
246
|
+
# then it will advance both arrows.
|
|
247
|
+
#
|
|
248
|
+
# Otherwise, one of the arrows is pointing to an element of its sequence that
|
|
249
|
+
# is not part of the longest common subsequence. #traverse_sequences will
|
|
250
|
+
# advance that arrow and will call <tt>callbacks#discard_a</tt> or
|
|
251
|
+
# <tt>callbacks#discard_b</tt>, depending on which arrow it advanced. If both
|
|
252
|
+
# arrows point to elements that are not part of the longest common
|
|
253
|
+
# subsequence, then #traverse_sequences will advance arrow +a+ and call the
|
|
254
|
+
# appropriate callback, then it will advance arrow +b+ and call the appropriate
|
|
255
|
+
# callback.
|
|
256
|
+
#
|
|
257
|
+
# The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, and
|
|
258
|
+
# <tt>callbacks#discard_b</tt> are invoked with an event comprising the
|
|
259
|
+
# action ("=", "+", or "-", respectively), the indicies +i+ and +j+, and the
|
|
260
|
+
# elements <tt>A[i]</tt> and <tt>B[j]</tt>. Return values are discarded by
|
|
261
|
+
# #traverse_sequences.
|
|
247
262
|
#
|
|
248
263
|
# === End of Sequences
|
|
249
264
|
#
|
|
250
265
|
# If arrow +a+ reaches the end of its sequence before arrow +b+ does,
|
|
251
|
-
# #traverse_sequence will try to call <tt>callbacks#finished_a</tt> with
|
|
252
|
-
#
|
|
253
|
-
#
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
#
|
|
266
|
+
# #traverse_sequence will try to call <tt>callbacks#finished_a</tt> with the
|
|
267
|
+
# last index and element of +A+ (<tt>A[-1]</tt>) and the current index and
|
|
268
|
+
# element of +B+ (<tt>B[j]</tt>). If <tt>callbacks#finished_a</tt> does not
|
|
269
|
+
# exist, then <tt>callbacks#discard_b</tt> will be called on each element of
|
|
270
|
+
# +B+ until the end of the sequence is reached (the call will be done with
|
|
271
|
+
# <tt>A[-1]</tt> and <tt>B[j]</tt> for each element).
|
|
257
272
|
#
|
|
258
273
|
# If +b+ reaches the end of +B+ before +a+ reaches the end of +A+,
|
|
259
274
|
# <tt>callbacks#finished_b</tt> will be called with the current index and
|
|
260
275
|
# element of +A+ (<tt>A[i]</tt>) and the last index and element of +B+
|
|
261
|
-
# (<tt>A[-1]</tt>). Again, if <tt>callbacks#finished_b</tt> does not exist
|
|
262
|
-
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
276
|
+
# (<tt>A[-1]</tt>). Again, if <tt>callbacks#finished_b</tt> does not exist on
|
|
277
|
+
# the callback object, then <tt>callbacks#discard_a</tt> will be called on
|
|
278
|
+
# each element of +A+ until the end of the sequence is reached (<tt>A[i]</tt>
|
|
279
|
+
# and <tt>B[-1]</tt>).
|
|
265
280
|
#
|
|
266
281
|
# There is a chance that one additional <tt>callbacks#discard_a</tt> or
|
|
267
|
-
# <tt>callbacks#discard_b</tt> will be called after the end of the
|
|
268
|
-
#
|
|
269
|
-
#
|
|
270
|
-
def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks
|
|
282
|
+
# <tt>callbacks#discard_b</tt> will be called after the end of the sequence
|
|
283
|
+
# is reached, if +a+ has not yet reached the end of +A+ or +b+ has not yet
|
|
284
|
+
# reached the end of +B+.
|
|
285
|
+
def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks) # :yields: change events
|
|
271
286
|
callbacks ||= Diff::LCS::SequenceCallbacks
|
|
272
287
|
matches = Diff::LCS::Internals.lcs(seq1, seq2)
|
|
273
288
|
|
|
274
289
|
run_finished_a = run_finished_b = false
|
|
275
|
-
string = seq1.
|
|
290
|
+
string = seq1.is_a?(String)
|
|
276
291
|
|
|
277
292
|
a_size = seq1.size
|
|
278
293
|
b_size = seq2.size
|
|
279
294
|
ai = bj = 0
|
|
280
295
|
|
|
281
|
-
|
|
282
|
-
b_line = matches[i]
|
|
283
|
-
|
|
284
|
-
ax = string ? seq1[i, 1] : seq1[i]
|
|
285
|
-
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
286
|
-
|
|
296
|
+
matches.each do |b_line|
|
|
287
297
|
if b_line.nil?
|
|
288
|
-
unless
|
|
289
|
-
|
|
298
|
+
unless seq1[ai].nil?
|
|
299
|
+
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
300
|
+
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
301
|
+
|
|
302
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
290
303
|
event = yield event if block_given?
|
|
291
304
|
callbacks.discard_a(event)
|
|
292
305
|
end
|
|
293
306
|
else
|
|
307
|
+
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
308
|
+
|
|
294
309
|
loop do
|
|
295
310
|
break unless bj < b_line
|
|
311
|
+
|
|
296
312
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
297
|
-
event = Diff::LCS::ContextChange.new(
|
|
313
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
298
314
|
event = yield event if block_given?
|
|
299
315
|
callbacks.discard_b(event)
|
|
300
316
|
bj += 1
|
|
301
317
|
end
|
|
302
318
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
303
|
-
event = Diff::LCS::ContextChange.new(
|
|
319
|
+
event = Diff::LCS::ContextChange.new("=", ai, ax, bj, bx)
|
|
304
320
|
event = yield event if block_given?
|
|
305
321
|
callbacks.match(event)
|
|
306
322
|
bj += 1
|
|
307
323
|
end
|
|
308
|
-
ai
|
|
324
|
+
ai += 1
|
|
309
325
|
end
|
|
310
|
-
ai += 1
|
|
311
326
|
|
|
312
|
-
# The last entry (if any) processed was a match. +ai+ and +bj+ point
|
|
313
|
-
#
|
|
314
|
-
while (ai < a_size)
|
|
327
|
+
# The last entry (if any) processed was a match. +ai+ and +bj+ point just
|
|
328
|
+
# past the last matching lines in their sequences.
|
|
329
|
+
while (ai < a_size) || (bj < b_size)
|
|
315
330
|
# last A?
|
|
316
|
-
if ai == a_size
|
|
317
|
-
if callbacks.respond_to?(:finished_a)
|
|
331
|
+
if ai == a_size && bj < b_size
|
|
332
|
+
if callbacks.respond_to?(:finished_a) && !run_finished_a
|
|
318
333
|
ax = string ? seq1[-1, 1] : seq1[-1]
|
|
319
334
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
320
|
-
event = Diff::LCS::ContextChange.new(
|
|
335
|
+
event = Diff::LCS::ContextChange.new(">", (a_size - 1), ax, bj, bx)
|
|
321
336
|
event = yield event if block_given?
|
|
322
337
|
callbacks.finished_a(event)
|
|
323
338
|
run_finished_a = true
|
|
@@ -325,7 +340,7 @@ class << Diff::LCS
|
|
|
325
340
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
326
341
|
loop do
|
|
327
342
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
328
|
-
event = Diff::LCS::ContextChange.new(
|
|
343
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
329
344
|
event = yield event if block_given?
|
|
330
345
|
callbacks.discard_b(event)
|
|
331
346
|
bj += 1
|
|
@@ -335,11 +350,11 @@ class << Diff::LCS
|
|
|
335
350
|
end
|
|
336
351
|
|
|
337
352
|
# last B?
|
|
338
|
-
if bj == b_size
|
|
339
|
-
if callbacks.respond_to?(:finished_b)
|
|
353
|
+
if bj == b_size && ai < a_size
|
|
354
|
+
if callbacks.respond_to?(:finished_b) && !run_finished_b
|
|
340
355
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
341
356
|
bx = string ? seq2[-1, 1] : seq2[-1]
|
|
342
|
-
event = Diff::LCS::ContextChange.new(
|
|
357
|
+
event = Diff::LCS::ContextChange.new("<", ai, ax, (b_size - 1), bx)
|
|
343
358
|
event = yield event if block_given?
|
|
344
359
|
callbacks.finished_b(event)
|
|
345
360
|
run_finished_b = true
|
|
@@ -347,7 +362,7 @@ class << Diff::LCS
|
|
|
347
362
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
348
363
|
loop do
|
|
349
364
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
350
|
-
event = Diff::LCS::ContextChange.new(
|
|
365
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
351
366
|
event = yield event if block_given?
|
|
352
367
|
callbacks.discard_a(event)
|
|
353
368
|
ai += 1
|
|
@@ -359,7 +374,7 @@ class << Diff::LCS
|
|
|
359
374
|
if ai < a_size
|
|
360
375
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
361
376
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
362
|
-
event = Diff::LCS::ContextChange.new(
|
|
377
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
363
378
|
event = yield event if block_given?
|
|
364
379
|
callbacks.discard_a(event)
|
|
365
380
|
ai += 1
|
|
@@ -368,7 +383,7 @@ class << Diff::LCS
|
|
|
368
383
|
if bj < b_size
|
|
369
384
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
370
385
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
371
|
-
event = Diff::LCS::ContextChange.new(
|
|
386
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
372
387
|
event = yield event if block_given?
|
|
373
388
|
callbacks.discard_b(event)
|
|
374
389
|
bj += 1
|
|
@@ -377,13 +392,13 @@ class << Diff::LCS
|
|
|
377
392
|
end
|
|
378
393
|
|
|
379
394
|
# #traverse_balanced is an alternative to #traverse_sequences. It uses a
|
|
380
|
-
# different algorithm to iterate through the entries in the computed
|
|
381
|
-
#
|
|
382
|
-
#
|
|
395
|
+
# different algorithm to iterate through the entries in the computed longest
|
|
396
|
+
# common subsequence. Instead of viewing the changes as insertions or
|
|
397
|
+
# deletions from one of the sequences, #traverse_balanced will report
|
|
383
398
|
# <em>changes</em> between the sequences.
|
|
384
399
|
#
|
|
385
|
-
# The arguments to #traverse_balanced are the two sequences to traverse
|
|
386
|
-
#
|
|
400
|
+
# The arguments to #traverse_balanced are the two sequences to traverse and a
|
|
401
|
+
# callback object, like this:
|
|
387
402
|
#
|
|
388
403
|
# traverse_balanced(seq1, seq2, Diff::LCS::ContextDiffCallbacks.new)
|
|
389
404
|
#
|
|
@@ -419,24 +434,23 @@ class << Diff::LCS
|
|
|
419
434
|
#
|
|
420
435
|
# === Matches
|
|
421
436
|
#
|
|
422
|
-
# If there are two arrows (+a+ and +b+) pointing to elements of sequences
|
|
423
|
-
#
|
|
424
|
-
#
|
|
425
|
-
#
|
|
426
|
-
#
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
432
|
-
#
|
|
433
|
-
# advance both arrows.
|
|
437
|
+
# If there are two arrows (+a+ and +b+) pointing to elements of sequences +A+
|
|
438
|
+
# and +B+, the arrows will initially point to the first elements of their
|
|
439
|
+
# respective sequences. #traverse_sequences will advance the arrows through
|
|
440
|
+
# the sequences one element at a time, calling a method on the user-specified
|
|
441
|
+
# callback object before each advance. It will advance the arrows in such a
|
|
442
|
+
# way that if there are elements <tt>A[i]</tt> and <tt>B[j]</tt> which are
|
|
443
|
+
# both equal and part of the longest common subsequence, there will be some
|
|
444
|
+
# moment during the execution of #traverse_sequences when arrow +a+ is
|
|
445
|
+
# pointing to <tt>A[i]</tt> and arrow +b+ is pointing to <tt>B[j]</tt>. When
|
|
446
|
+
# this happens, #traverse_sequences will call <tt>callbacks#match</tt> and
|
|
447
|
+
# then it will advance both arrows.
|
|
434
448
|
#
|
|
435
449
|
# === Discards
|
|
436
450
|
#
|
|
437
|
-
# Otherwise, one of the arrows is pointing to an element of its sequence
|
|
438
|
-
#
|
|
439
|
-
#
|
|
451
|
+
# Otherwise, one of the arrows is pointing to an element of its sequence that
|
|
452
|
+
# is not part of the longest common subsequence. #traverse_sequences will
|
|
453
|
+
# advance that arrow and will call <tt>callbacks#discard_a</tt> or
|
|
440
454
|
# <tt>callbacks#discard_b</tt>, depending on which arrow it advanced.
|
|
441
455
|
#
|
|
442
456
|
# === Changes
|
|
@@ -450,64 +464,65 @@ class << Diff::LCS
|
|
|
450
464
|
#
|
|
451
465
|
# The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>,
|
|
452
466
|
# <tt>callbacks#discard_b</tt>, and <tt>callbacks#change</tt> are invoked
|
|
453
|
-
# with an event comprising the action ("=", "+", "-", or "!",
|
|
454
|
-
#
|
|
455
|
-
#
|
|
456
|
-
# #traverse_balanced.
|
|
467
|
+
# with an event comprising the action ("=", "+", "-", or "!", respectively),
|
|
468
|
+
# the indicies +i+ and +j+, and the elements <tt>A[i]</tt> and <tt>B[j]</tt>.
|
|
469
|
+
# Return values are discarded by #traverse_balanced.
|
|
457
470
|
#
|
|
458
471
|
# === Context
|
|
459
|
-
#
|
|
460
|
-
# and +
|
|
472
|
+
#
|
|
473
|
+
# Note that +i+ and +j+ may not be the same index position, even if +a+ and
|
|
474
|
+
# +b+ are considered to be pointing to matching or changed elements.
|
|
461
475
|
def traverse_balanced(seq1, seq2, callbacks = Diff::LCS::BalancedCallbacks)
|
|
462
476
|
matches = Diff::LCS::Internals.lcs(seq1, seq2)
|
|
463
477
|
a_size = seq1.size
|
|
464
478
|
b_size = seq2.size
|
|
465
479
|
ai = bj = mb = 0
|
|
466
480
|
ma = -1
|
|
467
|
-
string = seq1.
|
|
481
|
+
string = seq1.is_a?(String)
|
|
468
482
|
|
|
469
483
|
# Process all the lines in the match vector.
|
|
470
484
|
loop do
|
|
471
485
|
# Find next match indices +ma+ and +mb+
|
|
472
486
|
loop do
|
|
473
487
|
ma += 1
|
|
474
|
-
break unless ma < matches.size
|
|
488
|
+
break unless ma < matches.size && matches[ma].nil?
|
|
475
489
|
end
|
|
476
490
|
|
|
477
491
|
break if ma >= matches.size # end of matches?
|
|
492
|
+
|
|
478
493
|
mb = matches[ma]
|
|
479
494
|
|
|
480
495
|
# Change(seq2)
|
|
481
|
-
while (ai < ma)
|
|
496
|
+
while (ai < ma) || (bj < mb)
|
|
482
497
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
483
498
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
484
499
|
|
|
485
500
|
case [(ai < ma), (bj < mb)]
|
|
486
501
|
when [true, true]
|
|
487
502
|
if callbacks.respond_to?(:change)
|
|
488
|
-
event = Diff::LCS::ContextChange.new(
|
|
503
|
+
event = Diff::LCS::ContextChange.new("!", ai, ax, bj, bx)
|
|
489
504
|
event = yield event if block_given?
|
|
490
505
|
callbacks.change(event)
|
|
491
506
|
ai += 1
|
|
492
|
-
bj += 1
|
|
493
507
|
else
|
|
494
|
-
event = Diff::LCS::ContextChange.new(
|
|
508
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
495
509
|
event = yield event if block_given?
|
|
496
510
|
callbacks.discard_a(event)
|
|
497
511
|
ai += 1
|
|
498
512
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
499
|
-
event = Diff::LCS::ContextChange.new(
|
|
513
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
500
514
|
event = yield event if block_given?
|
|
501
515
|
callbacks.discard_b(event)
|
|
502
|
-
bj += 1
|
|
503
516
|
end
|
|
517
|
+
|
|
518
|
+
bj += 1
|
|
504
519
|
when [true, false]
|
|
505
|
-
event = Diff::LCS::ContextChange.new(
|
|
520
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
506
521
|
event = yield event if block_given?
|
|
507
522
|
callbacks.discard_a(event)
|
|
508
523
|
ai += 1
|
|
509
524
|
when [false, true]
|
|
510
|
-
event = Diff::LCS::ContextChange.new(
|
|
525
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
511
526
|
event = yield event if block_given?
|
|
512
527
|
callbacks.discard_b(event)
|
|
513
528
|
bj += 1
|
|
@@ -517,43 +532,43 @@ class << Diff::LCS
|
|
|
517
532
|
# Match
|
|
518
533
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
519
534
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
520
|
-
event = Diff::LCS::ContextChange.new(
|
|
535
|
+
event = Diff::LCS::ContextChange.new("=", ai, ax, bj, bx)
|
|
521
536
|
event = yield event if block_given?
|
|
522
537
|
callbacks.match(event)
|
|
523
538
|
ai += 1
|
|
524
539
|
bj += 1
|
|
525
540
|
end
|
|
526
541
|
|
|
527
|
-
while (ai < a_size)
|
|
542
|
+
while (ai < a_size) || (bj < b_size)
|
|
528
543
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
529
544
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
|
530
545
|
|
|
531
546
|
case [(ai < a_size), (bj < b_size)]
|
|
532
547
|
when [true, true]
|
|
533
548
|
if callbacks.respond_to?(:change)
|
|
534
|
-
event = Diff::LCS::ContextChange.new(
|
|
549
|
+
event = Diff::LCS::ContextChange.new("!", ai, ax, bj, bx)
|
|
535
550
|
event = yield event if block_given?
|
|
536
551
|
callbacks.change(event)
|
|
537
552
|
ai += 1
|
|
538
|
-
bj += 1
|
|
539
553
|
else
|
|
540
|
-
event = Diff::LCS::ContextChange.new(
|
|
554
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
541
555
|
event = yield event if block_given?
|
|
542
556
|
callbacks.discard_a(event)
|
|
543
557
|
ai += 1
|
|
544
558
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
|
545
|
-
event = Diff::LCS::ContextChange.new(
|
|
559
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
546
560
|
event = yield event if block_given?
|
|
547
561
|
callbacks.discard_b(event)
|
|
548
|
-
bj += 1
|
|
549
562
|
end
|
|
563
|
+
|
|
564
|
+
bj += 1
|
|
550
565
|
when [true, false]
|
|
551
|
-
event = Diff::LCS::ContextChange.new(
|
|
566
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
|
552
567
|
event = yield event if block_given?
|
|
553
568
|
callbacks.discard_a(event)
|
|
554
569
|
ai += 1
|
|
555
570
|
when [false, true]
|
|
556
|
-
event = Diff::LCS::ContextChange.new(
|
|
571
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
|
557
572
|
event = yield event if block_given?
|
|
558
573
|
callbacks.discard_b(event)
|
|
559
574
|
bj += 1
|
|
@@ -561,10 +576,12 @@ class << Diff::LCS
|
|
|
561
576
|
end
|
|
562
577
|
end
|
|
563
578
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
:
|
|
567
|
-
|
|
579
|
+
# standard:disable Style/HashSyntax
|
|
580
|
+
PATCH_MAP = { # :nodoc:
|
|
581
|
+
:patch => {"+" => "+", "-" => "-", "!" => "!", "=" => "="}.freeze,
|
|
582
|
+
:unpatch => {"+" => "-", "-" => "+", "!" => "!", "=" => "="}.freeze
|
|
583
|
+
}.freeze
|
|
584
|
+
# standard:enable Style/HashSyntax
|
|
568
585
|
|
|
569
586
|
# Applies a +patchset+ to the sequence +src+ according to the +direction+
|
|
570
587
|
# (<tt>:patch</tt> or <tt>:unpatch</tt>), producing a new sequence.
|
|
@@ -577,23 +594,23 @@ class << Diff::LCS
|
|
|
577
594
|
#
|
|
578
595
|
# patch(s1, diff(s1, s2)) -> s2
|
|
579
596
|
#
|
|
580
|
-
# A +patchset+ can be considered to apply backward (<tt>:unpatch</tt>) if
|
|
581
|
-
#
|
|
597
|
+
# A +patchset+ can be considered to apply backward (<tt>:unpatch</tt>) if the
|
|
598
|
+
# following expression is true:
|
|
582
599
|
#
|
|
583
600
|
# patch(s2, diff(s1, s2)) -> s1
|
|
584
601
|
#
|
|
585
|
-
# If the +patchset+ contains no changes, the +src+ value will be returned
|
|
586
|
-
#
|
|
587
|
-
#
|
|
602
|
+
# If the +patchset+ contains no changes, the +src+ value will be returned as
|
|
603
|
+
# either <tt>src.dup</tt> or +src+. A +patchset+ can be deemed as having no
|
|
604
|
+
# changes if the following predicate returns true:
|
|
588
605
|
#
|
|
589
606
|
# patchset.empty? or
|
|
590
|
-
# patchset.flatten.all? { |change| change.unchanged? }
|
|
607
|
+
# patchset.flatten(1).all? { |change| change.unchanged? }
|
|
591
608
|
#
|
|
592
609
|
# === Patchsets
|
|
593
610
|
#
|
|
594
|
-
# A +patchset+ is always an enumerable sequence of changes, hunks of
|
|
595
|
-
#
|
|
596
|
-
#
|
|
611
|
+
# A +patchset+ is always an enumerable sequence of changes, hunks of changes,
|
|
612
|
+
# or a mix of the two. A hunk of changes is an enumerable sequence of
|
|
613
|
+
# changes:
|
|
597
614
|
#
|
|
598
615
|
# [ # patchset
|
|
599
616
|
# # change
|
|
@@ -602,20 +619,17 @@ class << Diff::LCS
|
|
|
602
619
|
# ]
|
|
603
620
|
# ]
|
|
604
621
|
#
|
|
605
|
-
# The +patch+ method accepts <tt>patchset</tt>s that are enumerable
|
|
606
|
-
#
|
|
607
|
-
#
|
|
622
|
+
# The +patch+ method accepts <tt>patchset</tt>s that are enumerable sequences
|
|
623
|
+
# containing either Diff::LCS::Change objects (or a subclass) or the array
|
|
624
|
+
# representations of those objects. Prior to application, array
|
|
608
625
|
# representations of Diff::LCS::Change objects will be reified.
|
|
609
626
|
def patch(src, patchset, direction = nil)
|
|
610
627
|
# Normalize the patchset.
|
|
611
628
|
has_changes, patchset = Diff::LCS::Internals.analyze_patchset(patchset)
|
|
612
629
|
|
|
613
|
-
|
|
614
|
-
return src.dup if src.respond_to? :dup
|
|
615
|
-
return src
|
|
616
|
-
end
|
|
630
|
+
return src.respond_to?(:dup) ? src.dup : src unless has_changes
|
|
617
631
|
|
|
618
|
-
string = src.
|
|
632
|
+
string = src.is_a?(String)
|
|
619
633
|
# Start with a new empty type of the source's class
|
|
620
634
|
res = src.class.new
|
|
621
635
|
|
|
@@ -625,7 +639,7 @@ class << Diff::LCS
|
|
|
625
639
|
|
|
626
640
|
patch_map = PATCH_MAP[direction]
|
|
627
641
|
|
|
628
|
-
patchset.
|
|
642
|
+
patchset.each do |change|
|
|
629
643
|
# Both Change and ContextChange support #action
|
|
630
644
|
action = patch_map[change.action]
|
|
631
645
|
|
|
@@ -643,23 +657,23 @@ class << Diff::LCS
|
|
|
643
657
|
end
|
|
644
658
|
|
|
645
659
|
case action
|
|
646
|
-
when
|
|
660
|
+
when "-" # Remove details from the old string
|
|
647
661
|
while ai < op
|
|
648
662
|
res << (string ? src[ai, 1] : src[ai])
|
|
649
663
|
ai += 1
|
|
650
664
|
bj += 1
|
|
651
665
|
end
|
|
652
666
|
ai += 1
|
|
653
|
-
when
|
|
667
|
+
when "+"
|
|
654
668
|
while bj < np
|
|
655
669
|
res << (string ? src[ai, 1] : src[ai])
|
|
656
670
|
ai += 1
|
|
657
671
|
bj += 1
|
|
658
672
|
end
|
|
659
673
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
when
|
|
674
|
+
res << el
|
|
675
|
+
bj += 1
|
|
676
|
+
when "="
|
|
663
677
|
# This only appears in sdiff output with the SDiff callback.
|
|
664
678
|
# Therefore, we only need to worry about dealing with a single
|
|
665
679
|
# element.
|
|
@@ -667,28 +681,28 @@ class << Diff::LCS
|
|
|
667
681
|
|
|
668
682
|
ai += 1
|
|
669
683
|
bj += 1
|
|
670
|
-
when
|
|
684
|
+
when "!"
|
|
671
685
|
while ai < op
|
|
672
686
|
res << (string ? src[ai, 1] : src[ai])
|
|
673
687
|
ai += 1
|
|
674
688
|
bj += 1
|
|
675
689
|
end
|
|
676
690
|
|
|
677
|
-
|
|
678
|
-
|
|
691
|
+
bj += 1
|
|
692
|
+
ai += 1
|
|
679
693
|
|
|
680
|
-
|
|
694
|
+
res << el
|
|
681
695
|
end
|
|
682
696
|
when Diff::LCS::Change
|
|
683
697
|
case action
|
|
684
|
-
when
|
|
698
|
+
when "-"
|
|
685
699
|
while ai < change.position
|
|
686
700
|
res << (string ? src[ai, 1] : src[ai])
|
|
687
701
|
ai += 1
|
|
688
702
|
bj += 1
|
|
689
703
|
end
|
|
690
704
|
ai += 1
|
|
691
|
-
when
|
|
705
|
+
when "+"
|
|
692
706
|
while bj < change.position
|
|
693
707
|
res << (string ? src[ai, 1] : src[ai])
|
|
694
708
|
ai += 1
|
|
@@ -711,15 +725,17 @@ class << Diff::LCS
|
|
|
711
725
|
res
|
|
712
726
|
end
|
|
713
727
|
|
|
714
|
-
# Given a set of patchset, convert the current version to the prior
|
|
715
|
-
#
|
|
728
|
+
# Given a set of patchset, convert the current version to the prior version.
|
|
729
|
+
# Does no auto-discovery.
|
|
716
730
|
def unpatch!(src, patchset)
|
|
717
731
|
patch(src, patchset, :unpatch)
|
|
718
732
|
end
|
|
719
733
|
|
|
720
|
-
# Given a set of patchset, convert the current version to the next
|
|
721
|
-
#
|
|
734
|
+
# Given a set of patchset, convert the current version to the next version.
|
|
735
|
+
# Does no auto-discovery.
|
|
722
736
|
def patch!(src, patchset)
|
|
723
737
|
patch(src, patchset, :patch)
|
|
724
738
|
end
|
|
725
739
|
end
|
|
740
|
+
|
|
741
|
+
require "diff/lcs/backports"
|