diff-lcs 1.3 → 1.6.2

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