diff-lcs 1.3 → 1.5.0

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.
Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/Contributing.md +84 -48
  3. data/History.md +334 -154
  4. data/Manifest.txt +23 -1
  5. data/README.rdoc +10 -10
  6. data/Rakefile +85 -21
  7. data/bin/htmldiff +7 -4
  8. data/bin/ldiff +4 -1
  9. data/lib/diff/lcs/array.rb +1 -1
  10. data/lib/diff/lcs/backports.rb +9 -0
  11. data/lib/diff/lcs/block.rb +1 -1
  12. data/lib/diff/lcs/callbacks.rb +15 -12
  13. data/lib/diff/lcs/change.rb +30 -37
  14. data/lib/diff/lcs/htmldiff.rb +17 -16
  15. data/lib/diff/lcs/hunk.rb +156 -74
  16. data/lib/diff/lcs/internals.rb +43 -42
  17. data/lib/diff/lcs/ldiff.rb +46 -42
  18. data/lib/diff/lcs/string.rb +1 -1
  19. data/lib/diff/lcs.rb +188 -174
  20. data/lib/diff-lcs.rb +1 -1
  21. data/spec/change_spec.rb +31 -7
  22. data/spec/diff_spec.rb +16 -12
  23. data/spec/fixtures/aX +1 -0
  24. data/spec/fixtures/bXaX +1 -0
  25. data/spec/fixtures/ldiff/output.diff +4 -0
  26. data/spec/fixtures/ldiff/output.diff-c +7 -0
  27. data/spec/fixtures/ldiff/output.diff-e +3 -0
  28. data/spec/fixtures/ldiff/output.diff-f +3 -0
  29. data/spec/fixtures/ldiff/output.diff-u +5 -0
  30. data/spec/fixtures/ldiff/output.diff.chef +4 -0
  31. data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
  32. data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
  33. data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
  34. data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
  35. data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
  36. data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
  37. data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
  38. data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
  39. data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
  40. data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
  41. data/spec/fixtures/new-chef +4 -0
  42. data/spec/fixtures/new-chef2 +17 -0
  43. data/spec/fixtures/old-chef +4 -0
  44. data/spec/fixtures/old-chef2 +14 -0
  45. data/spec/hunk_spec.rb +37 -26
  46. data/spec/issues_spec.rb +115 -10
  47. data/spec/lcs_spec.rb +10 -10
  48. data/spec/ldiff_spec.rb +71 -31
  49. data/spec/patch_spec.rb +93 -99
  50. data/spec/sdiff_spec.rb +89 -89
  51. data/spec/spec_helper.rb +118 -65
  52. data/spec/traverse_balanced_spec.rb +173 -173
  53. data/spec/traverse_sequences_spec.rb +29 -31
  54. metadata +54 -33
  55. data/autotest/discover.rb +0 -1
data/lib/diff/lcs.rb CHANGED
@@ -1,24 +1,24 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
3
+ module Diff; end unless defined? Diff # rubocop:disable Style/Documentation
2
4
 
3
- module Diff; end unless defined? Diff
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
- # they hard worked very hard on the algorithm until they found the right
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
- # because I am not very confident about this) was the `longest common
12
- # subsequence' method. In the LCS problem, you have two sequences of items:
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
- # some items, and from the second sequence by deleting other items. You also
21
- # want *S* to be as long as possible. In this case *S* is:
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
- # always pretty obvious, but that's not always the case, especially when the
35
- # two sequences have many repeated elements. For example, consider
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
- # b y c z+:
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 = '1.3'
52
+ VERSION = '1.5.0'
53
53
  end
54
54
 
55
55
  require 'diff/lcs/callbacks'
56
56
  require 'diff/lcs/internals'
57
57
 
58
- module Diff::LCS
58
+ module Diff::LCS # rubocop:disable Style/Documentation
59
59
  # Returns an Array containing the longest common subsequence(s) between
60
- # +self+ and +other+. See Diff::LCS#LCS.
60
+ # +self+ and +other+. See Diff::LCS#lcs.
61
61
  #
62
62
  # lcs = seq1.lcs(seq2)
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
63
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
- # based on +self+ and the +patchset+ will be created. See Diff::LCS#patch.
96
- # Attempts to autodiscover the direction of the patch.
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
- alias_method :unpatch, :patch
104
+ alias unpatch patch
101
105
 
102
- # Attempts to patch +self+ with the provided +patchset+. A new sequence
103
- # based on +self+ and the +patchset+ will be created. See Diff::LCS#patch.
104
- # Does no patch direction autodiscovery.
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
- # be replaced. See Diff::LCS#patch. Does no patch direction autodiscovery.
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
- # #unpatch!. If the sequence this is used on supports #replace, the value
129
- # of +self+ will be replaced. See Diff::LCS#unpatch. Does no patch direction
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))
@@ -142,29 +145,28 @@ class << Diff::LCS
142
145
  matches = Diff::LCS::Internals.lcs(seq1, seq2)
143
146
  ret = []
144
147
  string = seq1.kind_of? String
145
- matches.each_with_index do |e, i|
146
- unless matches[i].nil?
147
- v = string ? seq1[i, 1] : seq1[i]
148
- v = block[v] if block
149
- ret << v
150
- end
148
+ matches.each_with_index do |_e, 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
- alias_method :LCS, :lcs
157
+ alias 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
- # these changes.
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
- # to #finish, it will be called.
166
+ # initialise it. If the +callbacks+ object (possibly initialised) responds to
167
+ # #finish, it will be called.
165
168
  def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes:
166
- diff_traversal(:diff, seq1, seq2, callbacks || Diff::LCS::DiffCallbacks,
167
- &block)
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
- # to #finish, it will be called.
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
184
200
  def sdiff(seq1, seq2, callbacks = nil, &block) #:yields diff changes:
185
- diff_traversal(:sdiff, seq1, seq2, callbacks || Diff::LCS::SDiffCallbacks,
186
- &block)
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
- # module; #diff and #lcs are implemented as calls to it.
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
- # and a callback object, like this:
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,56 +233,56 @@ 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
- # +A+ and +B+, the arrows will initially point to the first elements of
223
- # their respective sequences. #traverse_sequences will advance the arrows
224
- # through the sequences one element at a time, calling a method on the
225
- # user-specified callback object before each advance. It will advance the
226
- # arrows in such a way that if there are elements <tt>A[i]</tt> and
227
- # <tt>B[j]</tt> which are both equal and part of the longest common
228
- # subsequence, there will be some moment during the execution of
229
- # #traverse_sequences when arrow +a+ is pointing to <tt>A[i]</tt> and
230
- # arrow +b+ is pointing to <tt>B[j]</tt>. When this happens,
231
- # #traverse_sequences will call <tt>callbacks#match</tt> and then it will
232
- # advance both arrows.
233
- #
234
- # Otherwise, one of the arrows is pointing to an element of its sequence
235
- # that is not part of the longest common subsequence. #traverse_sequences
236
- # will advance that arrow and will call <tt>callbacks#discard_a</tt> or
237
- # <tt>callbacks#discard_b</tt>, depending on which arrow it advanced. If
238
- # both arrows point to elements that are not part of the longest common
239
- # subsequence, then #traverse_sequences will advance one of them and call
240
- # the appropriate callback, but it is not specified which it will call.
241
- #
242
- # The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>,
243
- # and <tt>callbacks#discard_b</tt> are invoked with an event comprising
244
- # the action ("=", "+", or "-", respectively), the indicies +i+ and +j+,
245
- # and the elements <tt>A[i]</tt> and <tt>B[j]</tt>. Return values are
246
- # discarded by #traverse_sequences.
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
- # the last index and element of +A+ (<tt>A[-1]</tt>) and the current index
253
- # and element of +B+ (<tt>B[j]</tt>). If <tt>callbacks#finished_a</tt>
254
- # does not exist, then <tt>callbacks#discard_b</tt> will be called on each
255
- # element of +B+ until the end of the sequence is reached (the call will
256
- # be done with <tt>A[-1]</tt> and <tt>B[j]</tt> for each element).
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
- # on the callback object, then <tt>callbacks#discard_a</tt> will be called
263
- # on each element of +A+ until the end of the sequence is reached
264
- # (<tt>A[i]</tt> and <tt>B[-1]</tt>).
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
- # sequence is reached, if +a+ has not yet reached the end of +A+ or +b+
269
- # has not yet reached the end of +B+.
270
- def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks, &block) #:yields change events:
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
 
@@ -278,43 +293,43 @@ class << Diff::LCS
278
293
  b_size = seq2.size
279
294
  ai = bj = 0
280
295
 
281
- (0..matches.size).each do |i|
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 ax.nil? or (string and ax.empty?)
289
- event = Diff::LCS::ContextChange.new('-', i, ax, bj, bx)
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('+', i, ax, bj, bx)
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('=', i, ax, bj, bx)
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 = i
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
- # just past the last matching lines in their sequences.
327
+ # The last entry (if any) processed was a match. +ai+ and +bj+ point just
328
+ # past the last matching lines in their sequences.
314
329
  while (ai < a_size) or (bj < b_size)
315
330
  # last A?
316
331
  if ai == a_size and bj < b_size
317
- if callbacks.respond_to?(:finished_a) and not run_finished_a
332
+ if callbacks.respond_to?(:finished_a) and !run_finished_a
318
333
  ax = string ? seq1[-1, 1] : seq1[-1]
319
334
  bx = string ? seq2[bj, 1] : seq2[bj]
320
335
  event = Diff::LCS::ContextChange.new('>', (a_size - 1), ax, bj, bx)
@@ -336,7 +351,7 @@ class << Diff::LCS
336
351
 
337
352
  # last B?
338
353
  if bj == b_size and ai < a_size
339
- if callbacks.respond_to?(:finished_b) and not run_finished_b
354
+ if callbacks.respond_to?(:finished_b) and !run_finished_b
340
355
  ax = string ? seq1[ai, 1] : seq1[ai]
341
356
  bx = string ? seq2[-1, 1] : seq2[-1]
342
357
  event = Diff::LCS::ContextChange.new('<', ai, ax, (b_size - 1), bx)
@@ -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
- # longest common subsequence. Instead of viewing the changes as insertions
382
- # or deletions from one of the sequences, #traverse_balanced will report
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
- # and a callback object, like this:
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
- # +A+ and +B+, the arrows will initially point to the first elements of
424
- # their respective sequences. #traverse_sequences will advance the arrows
425
- # through the sequences one element at a time, calling a method on the
426
- # user-specified callback object before each advance. It will advance the
427
- # arrows in such a way that if there are elements <tt>A[i]</tt> and
428
- # <tt>B[j]</tt> which are both equal and part of the longest common
429
- # subsequence, there will be some moment during the execution of
430
- # #traverse_sequences when arrow +a+ is pointing to <tt>A[i]</tt> and
431
- # arrow +b+ is pointing to <tt>B[j]</tt>. When this happens,
432
- # #traverse_sequences will call <tt>callbacks#match</tt> and then it will
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
- # that is not part of the longest common subsequence. #traverse_sequences
439
- # will advance that arrow and will call <tt>callbacks#discard_a</tt> or
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,14 +464,14 @@ 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
- # respectively), the indicies +i+ and +j+, and the elements
455
- # <tt>A[i]</tt> and <tt>B[j]</tt>. Return values are discarded by
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
- # Note that +i+ and +j+ may not be the same index position, even if +a+
460
- # and +b+ are considered to be pointing to matching or changed elements.
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
@@ -475,6 +489,7 @@ class << Diff::LCS
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)
@@ -489,7 +504,6 @@ class << Diff::LCS
489
504
  event = yield event if block_given?
490
505
  callbacks.change(event)
491
506
  ai += 1
492
- bj += 1
493
507
  else
494
508
  event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx)
495
509
  event = yield event if block_given?
@@ -499,8 +513,9 @@ class << Diff::LCS
499
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
520
  event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx)
506
521
  event = yield event if block_given?
@@ -535,7 +550,6 @@ class << Diff::LCS
535
550
  event = yield event if block_given?
536
551
  callbacks.change(event)
537
552
  ai += 1
538
- bj += 1
539
553
  else
540
554
  event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx)
541
555
  event = yield event if block_given?
@@ -545,8 +559,9 @@ class << Diff::LCS
545
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
566
  event = Diff::LCS::ContextChange.new('-', ai, ax, bj, bx)
552
567
  event = yield event if block_given?
@@ -562,9 +577,9 @@ class << Diff::LCS
562
577
  end
563
578
 
564
579
  PATCH_MAP = { #:nodoc:
565
- :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' },
566
- :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' }
567
- }
580
+ :patch => { '+' => '+', '-' => '-', '!' => '!', '=' => '=' }.freeze,
581
+ :unpatch => { '+' => '-', '-' => '+', '!' => '!', '=' => '=' }.freeze
582
+ }.freeze
568
583
 
569
584
  # Applies a +patchset+ to the sequence +src+ according to the +direction+
570
585
  # (<tt>:patch</tt> or <tt>:unpatch</tt>), producing a new sequence.
@@ -577,23 +592,23 @@ class << Diff::LCS
577
592
  #
578
593
  # patch(s1, diff(s1, s2)) -> s2
579
594
  #
580
- # A +patchset+ can be considered to apply backward (<tt>:unpatch</tt>) if
581
- # the following expression is true:
595
+ # A +patchset+ can be considered to apply backward (<tt>:unpatch</tt>) if the
596
+ # following expression is true:
582
597
  #
583
598
  # patch(s2, diff(s1, s2)) -> s1
584
599
  #
585
- # If the +patchset+ contains no changes, the +src+ value will be returned
586
- # as either <tt>src.dup</tt> or +src+. A +patchset+ can be deemed as
587
- # having no changes if the following predicate returns true:
600
+ # If the +patchset+ contains no changes, the +src+ value will be returned as
601
+ # either <tt>src.dup</tt> or +src+. A +patchset+ can be deemed as having no
602
+ # changes if the following predicate returns true:
588
603
  #
589
604
  # patchset.empty? or
590
- # patchset.flatten.all? { |change| change.unchanged? }
605
+ # patchset.flatten(1).all? { |change| change.unchanged? }
591
606
  #
592
607
  # === Patchsets
593
608
  #
594
- # A +patchset+ is always an enumerable sequence of changes, hunks of
595
- # changes, or a mix of the two. A hunk of changes is an enumerable
596
- # sequence of changes:
609
+ # A +patchset+ is always an enumerable sequence of changes, hunks of changes,
610
+ # or a mix of the two. A hunk of changes is an enumerable sequence of
611
+ # changes:
597
612
  #
598
613
  # [ # patchset
599
614
  # # change
@@ -602,18 +617,15 @@ class << Diff::LCS
602
617
  # ]
603
618
  # ]
604
619
  #
605
- # The +patch+ method accepts <tt>patchset</tt>s that are enumerable
606
- # sequences containing either Diff::LCS::Change objects (or a subclass) or
607
- # the array representations of those objects. Prior to application, array
620
+ # The +patch+ method accepts <tt>patchset</tt>s that are enumerable sequences
621
+ # containing either Diff::LCS::Change objects (or a subclass) or the array
622
+ # representations of those objects. Prior to application, array
608
623
  # representations of Diff::LCS::Change objects will be reified.
609
624
  def patch(src, patchset, direction = nil)
610
625
  # Normalize the patchset.
611
626
  has_changes, patchset = Diff::LCS::Internals.analyze_patchset(patchset)
612
627
 
613
- if not has_changes
614
- return src.dup if src.respond_to? :dup
615
- return src
616
- end
628
+ return src.respond_to?(:dup) ? src.dup : src unless has_changes
617
629
 
618
630
  string = src.kind_of?(String)
619
631
  # Start with a new empty type of the source's class
@@ -625,7 +637,7 @@ class << Diff::LCS
625
637
 
626
638
  patch_map = PATCH_MAP[direction]
627
639
 
628
- patchset.flatten.each do |change|
640
+ patchset.each do |change|
629
641
  # Both Change and ContextChange support #action
630
642
  action = patch_map[change.action]
631
643
 
@@ -657,8 +669,8 @@ class << Diff::LCS
657
669
  bj += 1
658
670
  end
659
671
 
660
- res << el
661
- bj += 1
672
+ res << el
673
+ bj += 1
662
674
  when '='
663
675
  # This only appears in sdiff output with the SDiff callback.
664
676
  # Therefore, we only need to worry about dealing with a single
@@ -674,10 +686,10 @@ class << Diff::LCS
674
686
  bj += 1
675
687
  end
676
688
 
677
- bj += 1
678
- ai += 1
689
+ bj += 1
690
+ ai += 1
679
691
 
680
- res << el
692
+ res << el
681
693
  end
682
694
  when Diff::LCS::Change
683
695
  case action
@@ -711,15 +723,17 @@ class << Diff::LCS
711
723
  res
712
724
  end
713
725
 
714
- # Given a set of patchset, convert the current version to the prior
715
- # version. Does no auto-discovery.
726
+ # Given a set of patchset, convert the current version to the prior version.
727
+ # Does no auto-discovery.
716
728
  def unpatch!(src, patchset)
717
729
  patch(src, patchset, :unpatch)
718
730
  end
719
731
 
720
- # Given a set of patchset, convert the current version to the next
721
- # version. Does no auto-discovery.
732
+ # Given a set of patchset, convert the current version to the next version.
733
+ # Does no auto-discovery.
722
734
  def patch!(src, patchset)
723
735
  patch(src, patchset, :patch)
724
736
  end
725
737
  end
738
+
739
+ require 'diff/lcs/backports'
data/lib/diff-lcs.rb CHANGED
@@ -1,3 +1,3 @@
1
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'diff/lcs'