diff-lcs 1.5.1 → 2.0.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +581 -0
  3. data/CODE_OF_CONDUCT.md +166 -0
  4. data/CONTRIBUTING.md +127 -0
  5. data/CONTRIBUTORS.md +59 -0
  6. data/LICENCE.md +68 -0
  7. data/Manifest.txt +99 -35
  8. data/README.md +105 -0
  9. data/Rakefile +107 -96
  10. data/SECURITY.md +36 -0
  11. data/integration/compare/array_diff_spec.rb +10 -0
  12. data/integration/compare/hash_diff_spec.rb +25 -0
  13. data/integration/compare/string_diff_spec.rb +10 -0
  14. data/integration/rspec_differ_spec.rb +26 -0
  15. data/integration/rspec_expectations_spec.rb +32 -0
  16. data/integration/runner +20 -0
  17. data/lib/diff/lcs/block.rb +29 -24
  18. data/lib/diff/lcs/callbacks.rb +240 -242
  19. data/lib/diff/lcs/change.rb +102 -104
  20. data/lib/diff/lcs/hunk.rb +110 -157
  21. data/lib/diff/lcs/internals.rb +92 -96
  22. data/lib/diff/lcs/ldiff.rb +81 -73
  23. data/lib/diff/lcs/version.rb +7 -0
  24. data/lib/diff/lcs.rb +440 -466
  25. data/{docs → licenses}/artistic.txt +1 -1
  26. data/licenses/dco.txt +34 -0
  27. data/spec/hunk_spec.rb +33 -46
  28. data/spec/issues_spec.rb +32 -32
  29. data/spec/lcs_spec.rb +6 -6
  30. data/spec/ldiff_spec.rb +27 -16
  31. data/spec/patch_spec.rb +1 -1
  32. data/spec/spec_helper.rb +98 -108
  33. data/test/fixtures/123_x +2 -0
  34. data/test/fixtures/456_x +2 -0
  35. data/test/fixtures/empty +0 -0
  36. data/test/fixtures/file1.bin +0 -0
  37. data/test/fixtures/file2.bin +0 -0
  38. data/test/fixtures/four_lines +4 -0
  39. data/test/fixtures/four_lines_with_missing_new_line +4 -0
  40. data/test/fixtures/ldiff/diff.missing_new_line1-e +1 -0
  41. data/test/fixtures/ldiff/diff.missing_new_line1-f +1 -0
  42. data/test/fixtures/ldiff/diff.missing_new_line2-e +1 -0
  43. data/test/fixtures/ldiff/diff.missing_new_line2-f +1 -0
  44. data/test/fixtures/ldiff/error.diff.chef-e +2 -0
  45. data/test/fixtures/ldiff/error.diff.chef-f +2 -0
  46. data/test/fixtures/ldiff/error.diff.missing_new_line1-e +1 -0
  47. data/test/fixtures/ldiff/error.diff.missing_new_line1-f +1 -0
  48. data/test/fixtures/ldiff/error.diff.missing_new_line2-e +1 -0
  49. data/test/fixtures/ldiff/error.diff.missing_new_line2-f +1 -0
  50. data/test/fixtures/ldiff/output.diff-c +7 -0
  51. data/test/fixtures/ldiff/output.diff-u +5 -0
  52. data/test/fixtures/ldiff/output.diff.bin1 +0 -0
  53. data/test/fixtures/ldiff/output.diff.bin1-c +0 -0
  54. data/test/fixtures/ldiff/output.diff.bin1-e +0 -0
  55. data/test/fixtures/ldiff/output.diff.bin1-f +0 -0
  56. data/test/fixtures/ldiff/output.diff.bin1-u +0 -0
  57. data/test/fixtures/ldiff/output.diff.bin2 +1 -0
  58. data/test/fixtures/ldiff/output.diff.bin2-c +1 -0
  59. data/test/fixtures/ldiff/output.diff.bin2-e +1 -0
  60. data/test/fixtures/ldiff/output.diff.bin2-f +1 -0
  61. data/test/fixtures/ldiff/output.diff.bin2-u +1 -0
  62. data/{spec → test}/fixtures/ldiff/output.diff.chef-c +2 -2
  63. data/test/fixtures/ldiff/output.diff.chef-u +9 -0
  64. data/{spec → test}/fixtures/ldiff/output.diff.chef2-c +2 -2
  65. data/{spec → test}/fixtures/ldiff/output.diff.chef2-u +2 -2
  66. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines +5 -0
  67. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-c +9 -0
  68. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-e +6 -0
  69. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-f +6 -0
  70. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-u +7 -0
  71. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty +5 -0
  72. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-c +9 -0
  73. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-e +1 -0
  74. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-f +1 -0
  75. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-u +7 -0
  76. data/test/fixtures/ldiff/output.diff.issue95_trailing_context +4 -0
  77. data/test/fixtures/ldiff/output.diff.issue95_trailing_context-c +9 -0
  78. data/{spec/fixtures/ldiff/output.diff-e → test/fixtures/ldiff/output.diff.issue95_trailing_context-e} +1 -1
  79. data/{spec/fixtures/ldiff/output.diff-f → test/fixtures/ldiff/output.diff.issue95_trailing_context-f} +1 -1
  80. data/test/fixtures/ldiff/output.diff.issue95_trailing_context-u +6 -0
  81. data/test/fixtures/ldiff/output.diff.missing_new_line1 +5 -0
  82. data/test/fixtures/ldiff/output.diff.missing_new_line1-c +14 -0
  83. data/test/fixtures/ldiff/output.diff.missing_new_line1-e +0 -0
  84. data/test/fixtures/ldiff/output.diff.missing_new_line1-f +0 -0
  85. data/test/fixtures/ldiff/output.diff.missing_new_line1-u +9 -0
  86. data/test/fixtures/ldiff/output.diff.missing_new_line2 +5 -0
  87. data/test/fixtures/ldiff/output.diff.missing_new_line2-c +14 -0
  88. data/test/fixtures/ldiff/output.diff.missing_new_line2-e +0 -0
  89. data/test/fixtures/ldiff/output.diff.missing_new_line2-f +0 -0
  90. data/test/fixtures/ldiff/output.diff.missing_new_line2-u +9 -0
  91. data/test/test_block.rb +34 -0
  92. data/test/test_change.rb +234 -0
  93. data/test/test_diff.rb +53 -0
  94. data/test/test_helper.rb +225 -0
  95. data/test/test_hunk.rb +72 -0
  96. data/test/test_issues.rb +168 -0
  97. data/test/test_lcs.rb +47 -0
  98. data/test/test_ldiff.rb +89 -0
  99. data/test/test_patch.rb +362 -0
  100. data/test/test_sdiff.rb +167 -0
  101. data/test/test_traverse_balanced.rb +322 -0
  102. data/test/test_traverse_sequences.rb +187 -0
  103. metadata +211 -103
  104. data/.rspec +0 -1
  105. data/Code-of-Conduct.md +0 -74
  106. data/Contributing.md +0 -121
  107. data/History.md +0 -431
  108. data/License.md +0 -41
  109. data/README.rdoc +0 -84
  110. data/bin/htmldiff +0 -35
  111. data/lib/diff/lcs/backports.rb +0 -9
  112. data/lib/diff/lcs/htmldiff.rb +0 -158
  113. data/spec/fixtures/ldiff/output.diff-c +0 -7
  114. data/spec/fixtures/ldiff/output.diff-u +0 -5
  115. data/spec/fixtures/ldiff/output.diff.chef-e +0 -3
  116. data/spec/fixtures/ldiff/output.diff.chef-f +0 -3
  117. data/spec/fixtures/ldiff/output.diff.chef-u +0 -9
  118. data/spec/fixtures/ldiff/output.diff.chef2-e +0 -7
  119. data/spec/fixtures/ldiff/output.diff.chef2-f +0 -7
  120. /data/{docs → licenses}/COPYING.txt +0 -0
  121. /data/{spec → test}/fixtures/aX +0 -0
  122. /data/{spec → test}/fixtures/bXaX +0 -0
  123. /data/{spec → test}/fixtures/ds1.csv +0 -0
  124. /data/{spec → test}/fixtures/ds2.csv +0 -0
  125. /data/{spec → test}/fixtures/ldiff/output.diff +0 -0
  126. /data/{spec → test}/fixtures/ldiff/output.diff.chef +0 -0
  127. /data/{spec → test}/fixtures/ldiff/output.diff.chef2 +0 -0
  128. /data/{spec → test}/fixtures/ldiff/output.diff.chef2-d +0 -0
  129. /data/{spec → test}/fixtures/new-chef +0 -0
  130. /data/{spec → test}/fixtures/new-chef2 +0 -0
  131. /data/{spec → test}/fixtures/old-chef +0 -0
  132. /data/{spec → test}/fixtures/old-chef2 +0 -0
data/lib/diff/lcs/hunk.rb CHANGED
@@ -2,41 +2,40 @@
2
2
 
3
3
  require "diff/lcs/block"
4
4
 
5
- # A Hunk is a group of Blocks which overlap because of the context surrounding
6
- # each block. (So if we're not using context, every hunk will contain one
7
- # block.) Used in the diff program (bin/ldiff).
5
+ # A Hunk is a group of Blocks which overlap because of the context surrounding each block.
6
+ # (So if we're not using context, every hunk will contain one block.) Used in the diff
7
+ # program (bin/ldiff).
8
8
  class Diff::LCS::Hunk
9
9
  OLD_DIFF_OP_ACTION = {"+" => "a", "-" => "d", "!" => "c"}.freeze # :nodoc:
10
- ED_DIFF_OP_ACTION = {"+" => "a", "-" => "d", "!" => "c"}.freeze # :nodoc:
10
+ private_constant :OLD_DIFF_OP_ACTION
11
11
 
12
- private_constant :OLD_DIFF_OP_ACTION, :ED_DIFF_OP_ACTION if respond_to?(:private_constant)
13
-
14
- # Create a hunk using references to both the old and new data, as well as the
15
- # piece of data.
12
+ # Create a hunk using references to both the old and new data, as well as the piece of
13
+ # data.
16
14
  def initialize(data_old, data_new, piece, flag_context, file_length_difference)
17
15
  # At first, a hunk will have just one Block in it
18
- @blocks = [Diff::LCS::Block.new(piece)]
16
+ @blocks = [Diff::LCS::Block.from_chunk(piece)]
19
17
 
20
18
  if @blocks[0].remove.empty? && @blocks[0].insert.empty?
21
19
  fail "Cannot build a hunk from #{piece.inspect}; has no add or remove actions"
22
20
  end
23
21
 
24
- if String.method_defined?(:encoding)
25
- @preferred_data_encoding = data_old.fetch(0) { data_new.fetch(0, "") }.encoding
26
- end
22
+ @preferred_data_encoding = data_old.fetch(0) { data_new.fetch(0) { "" } }.encoding
23
+ @newline = "\n".encode(@preferred_data_encoding)
24
+ @missing_newline = "\".encode(@preferred_data_encoding)
27
25
 
28
26
  @data_old = data_old
29
27
  @data_new = data_new
28
+ @old_empty = data_old.empty? || (data_old.size == 1 && data_old[0].empty?)
29
+ @new_empty = data_new.empty? || (data_new.size == 1 && data_new[0].empty?)
30
30
 
31
31
  before = after = file_length_difference
32
32
  after += @blocks[0].diff_size
33
33
  @file_length_difference = after # The caller must get this manually
34
34
  @max_diff_size = @blocks.map { |e| e.diff_size.abs }.max
35
35
 
36
- # Save the start & end of each array. If the array doesn't exist (e.g.,
37
- # we're only adding items in this block), then figure out the line number
38
- # based on the line number of the other file and the current difference in
39
- # file lengths.
36
+ # Save the start and end of each array. If the array doesn't exist (e.g., we're only
37
+ # adding items in this block), then figure out the line number based on the line
38
+ # number of the other file and the current difference in file lengths.
40
39
  if @blocks[0].remove.empty?
41
40
  a1 = a2 = nil
42
41
  else
@@ -64,11 +63,13 @@ class Diff::LCS::Hunk
64
63
  attr_reader :end_old, :end_new
65
64
  attr_reader :file_length_difference
66
65
 
67
- # Change the "start" and "end" fields to note that context should be added
68
- # to this hunk.
69
- attr_accessor :flag_context
70
- undef :flag_context=
71
- def flag_context=(context) # :nodoc: # standard:disable Lint/DuplicateMethods
66
+ ##
67
+ # Change the "start" and "end" fields to note that context should be added to this hunk.
68
+ # :attr_accessor: :flag_context
69
+ attr_reader :flag_context
70
+
71
+ ##
72
+ def flag_context=(context) # :nodoc:
72
73
  return if context.nil? || context.zero?
73
74
 
74
75
  add_start = (context > @start_old) ? @start_old : context
@@ -79,21 +80,18 @@ class Diff::LCS::Hunk
79
80
  old_size = @data_old.size
80
81
 
81
82
  add_end =
82
- if (@end_old + context) > old_size
83
- old_size - @end_old
83
+ if (@end_old + context) >= old_size
84
+ old_size - @end_old - 1
84
85
  else
85
86
  context
86
87
  end
87
88
 
88
- add_end = @max_diff_size if add_end >= old_size
89
-
90
89
  @end_old += add_end
91
90
  @end_new += add_end
92
91
  end
93
92
 
94
- # Merges this hunk and the provided hunk together if they overlap. Returns
95
- # a truthy value so that if there is no overlap, you can know the merge
96
- # was skipped.
93
+ # Merges this hunk and the provided hunk together if they overlap. Returns a truthy
94
+ # value so that if there is no overlap, you can know the merge was skipped.
97
95
  def merge(hunk)
98
96
  return unless overlaps?(hunk)
99
97
 
@@ -103,12 +101,11 @@ class Diff::LCS::Hunk
103
101
  end
104
102
  alias_method :unshift, :merge
105
103
 
106
- # Determines whether there is an overlap between this hunk and the
107
- # provided hunk. This will be true if the difference between the two hunks
108
- # start or end positions is within one position of each other.
104
+ # Determines whether there is an overlap between this hunk and the provided hunk. This
105
+ # will be true if the difference between the two hunks start or end positions is within
106
+ # one position of each other.
109
107
  def overlaps?(hunk)
110
- hunk and (((@start_old - hunk.end_old) <= 1) or
111
- ((@start_new - hunk.end_new) <= 1))
108
+ hunk && (((@start_old - hunk.end_old) <= 1) || ((@start_new - hunk.end_new) <= 1))
112
109
  end
113
110
 
114
111
  # Returns a diff string based on a format.
@@ -120,182 +117,164 @@ class Diff::LCS::Hunk
120
117
  unified_diff(last)
121
118
  when :context
122
119
  context_diff(last)
123
- when :ed
124
- self
125
- when :reverse_ed, :ed_finish
126
- ed_diff(format, last)
127
120
  else
128
121
  fail "Unknown diff format #{format}."
129
122
  end
130
123
  end
131
124
 
132
- # Note that an old diff can't have any context. Therefore, we know that
133
- # there's only one block in the hunk.
134
- def old_diff(_last = false)
125
+ private
126
+
127
+ # Note that an old diff can't have any context. Therefore, we know that there's only one
128
+ # block in the hunk.
129
+ def old_diff(last = false)
135
130
  warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
136
131
 
132
+ del, ins, sep, _ = ["< ", "> ", "---\n", "\\n"]
133
+ .map { _1.encode(@preferred_data_encoding) }
134
+
137
135
  block = @blocks[0]
138
136
 
139
- # Calculate item number range. Old diff range is just like a context
140
- # diff range, except the ranges are on one line with the action between
141
- # them.
142
- s = encode("#{context_range(:old, ",")}#{OLD_DIFF_OP_ACTION[block.op]}#{context_range(:new, ",")}\n")
143
- # If removing anything, just print out all the remove lines in the hunk
144
- # which is just all the remove lines in the block.
137
+ if last
138
+ old_missing_newline = !@old_empty && missing_last_newline?(@data_old)
139
+ new_missing_newline = !@new_empty && missing_last_newline?(@data_new)
140
+ end
141
+
142
+ # Calculate item number range. Old diff range is just like a context diff range,
143
+ # except the ranges are on one line with the action between them.
144
+ s = "#{context_range(:old, ",")}#{OLD_DIFF_OP_ACTION[block.op]}#{context_range(:new, ",")}\n"
145
+ .encode(@preferred_data_encoding)
146
+ # If removing anything, just print out all the remove lines in the hunk which is just
147
+ # all the remove lines in the block.
145
148
  unless block.remove.empty?
146
- @data_old[@start_old..@end_old].each { |e| s << encode("< ") + e.chomp + encode("\n") }
149
+ @data_old[@start_old..@end_old].each { |e| s << del + e.chomp + @newline }
147
150
  end
148
151
 
149
- s << encode("---\n") if block.op == "!"
152
+ s << @missing_newline << @newline if old_missing_newline && !new_missing_newline
153
+ s << sep if block.op == "!"
150
154
 
151
155
  unless block.insert.empty?
152
- @data_new[@start_new..@end_new].each { |e| s << encode("> ") + e.chomp + encode("\n") }
156
+ @data_new[@start_new..@end_new].each { |e| s << ins + e.chomp + @newline }
153
157
  end
154
158
 
159
+ s << @missing_newline << @newline if new_missing_newline && !old_missing_newline
160
+
155
161
  s
156
162
  end
157
- private :old_diff
158
163
 
159
164
  def unified_diff(last = false)
160
165
  # Calculate item number range.
161
- s = encode("@@ -#{unified_range(:old, last)} +#{unified_range(:new, last)} @@\n")
166
+ s = "@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n"
167
+ .encode(@preferred_data_encoding)
162
168
 
163
- # Outlist starts containing the hunk of the old file. Removing an item
164
- # just means putting a '-' in front of it. Inserting an item requires
165
- # getting it from the new file and splicing it in. We splice in
166
- # +num_added+ items. Remove blocks use +num_added+ because splicing
167
- # changed the length of outlist.
169
+ # `outlist` starts containing the hunk of the old file. Removing an item just means
170
+ # putting a '-' in front of it. Inserting an item requires getting it from the new
171
+ # file and splicing it in. We splice in `num_added` items. Remove blocks use
172
+ # `num_added` because splicing changed the length of outlist.
168
173
  #
169
- # We remove +num_removed+ items. Insert blocks use +num_removed+
170
- # because their item numbers -- corresponding to positions in the NEW
171
- # file -- don't take removed items into account.
174
+ # We remove `num_removed` items. Insert blocks use `num_removed` because their item
175
+ # numbers -- corresponding to positions in the NEW file -- don't take removed items
176
+ # into account.
172
177
  lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0
173
178
 
174
- # standard:disable Performance/UnfreezeString
175
- outlist = @data_old[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
176
- # standard:enable Performance/UnfreezeString
179
+ space = " ".encode(@preferred_data_encoding)
180
+ outlist = @data_old[lo..hi].map { |e| "#{space}#{e.chomp}" }
177
181
 
178
182
  last_block = blocks[-1]
179
183
 
180
184
  if last
181
- old_missing_newline = missing_last_newline?(@data_old)
182
- new_missing_newline = missing_last_newline?(@data_new)
185
+ old_missing_newline = !@old_empty && missing_last_newline?(@data_old)
186
+ new_missing_newline = !@new_empty && missing_last_newline?(@data_new)
183
187
  end
184
188
 
185
189
  @blocks.each do |block|
186
190
  block.remove.each do |item|
187
- op = item.action.to_s # -
188
191
  offset = item.position - lo + num_added
189
- outlist[offset][0, 1] = encode(op)
192
+ outlist[offset][0, 1] = item.action.to_s.encode(@preferred_data_encoding) # -
190
193
  num_removed += 1
191
194
  end
192
195
 
193
196
  if last && block == last_block && old_missing_newline && !new_missing_newline
194
- outlist << encode('\')
197
+ outlist << @missing_newline
195
198
  num_removed += 1
196
199
  end
197
200
 
198
201
  block.insert.each do |item|
199
- op = item.action.to_s # +
202
+ op = item.action.to_s.encode(@preferred_data_encoding) # +
200
203
  offset = item.position - @start_new + num_removed
201
- outlist[offset, 0] = encode(op) + @data_new[item.position].chomp
204
+ outlist[offset, 0] = op + @data_new[item.position].chomp
202
205
  num_added += 1
203
206
  end
204
207
  end
205
208
 
206
- outlist << encode('\') if last && new_missing_newline
209
+ outlist << @missing_newline if last && new_missing_newline
207
210
 
208
- s << outlist.join(encode("\n"))
211
+ s << outlist.join("\n".encode(@preferred_data_encoding))
209
212
 
210
213
  s
211
214
  end
212
- private :unified_diff
213
215
 
214
216
  def context_diff(last = false)
215
- s = encode("***************\n")
216
- s << encode("*** #{context_range(:old, ",", last)} ****\n")
217
- r = context_range(:new, ",", last)
217
+ s = "***************\n".encode(@preferred_data_encoding)
218
+ s << "*** #{context_range(:old, ",")} ****\n".encode(@preferred_data_encoding)
219
+ r = context_range(:new, ",")
220
+
221
+ spaces = " ".encode(@preferred_data_encoding)
218
222
 
219
223
  if last
220
224
  old_missing_newline = missing_last_newline?(@data_old)
221
225
  new_missing_newline = missing_last_newline?(@data_new)
222
226
  end
223
227
 
224
- # Print out file 1 part for each block in context diff format if there
225
- # are any blocks that remove items
228
+ # Print out file 1 part for each block in context diff format if there are any blocks
229
+ # that remove items
226
230
  lo, hi = @start_old, @end_old
227
231
  removes = @blocks.reject { |e| e.remove.empty? }
228
232
 
229
233
  unless removes.empty?
230
- # standard:disable Performance/UnfreezeString
231
- outlist = @data_old[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
232
- # standard:enable Performance/UnfreezeString
234
+ outlist = @data_old[lo..hi].map { |e| "#{spaces}#{e.chomp}" }
233
235
 
234
236
  last_block = removes[-1]
235
237
 
236
238
  removes.each do |block|
237
239
  block.remove.each do |item|
238
- outlist[item.position - lo][0, 1] = encode(block.op) # - or !
240
+ outlist[item.position - lo][0, 1] = block.op.encode(@preferred_data_encoding) # - or !
239
241
  end
240
242
 
241
243
  if last && block == last_block && old_missing_newline
242
- outlist << encode('\')
244
+ outlist << @missing_newline
243
245
  end
244
246
  end
245
247
 
246
- s << outlist.join(encode("\n")) << encode("\n")
248
+ s << outlist.join(@newline) << @newline
247
249
  end
248
250
 
249
- s << encode("--- #{r} ----\n")
251
+ s << "--- #{r} ----\n".encode(@preferred_data_encoding)
250
252
  lo, hi = @start_new, @end_new
251
253
  inserts = @blocks.reject { |e| e.insert.empty? }
252
254
 
253
255
  unless inserts.empty?
254
- # standard:disable Performance/UnfreezeString
255
- outlist = @data_new[lo..hi].map { |e| String.new("#{encode(" ")}#{e.chomp}") }
256
- # standard:enable Performance/UnfreezeString
256
+ outlist = @data_new[lo..hi].map { |e| "#{spaces}#{e.chomp}" }
257
257
 
258
258
  last_block = inserts[-1]
259
259
 
260
260
  inserts.each do |block|
261
261
  block.insert.each do |item|
262
- outlist[item.position - lo][0, 1] = encode(block.op) # + or !
262
+ outlist[item.position - lo][0, 1] = block.op.encode(@preferred_data_encoding) # + or !
263
263
  end
264
264
 
265
265
  if last && block == last_block && new_missing_newline
266
- outlist << encode('\')
266
+ outlist << @missing_newline
267
267
  end
268
268
  end
269
- s << outlist.join(encode("\n"))
269
+ s << outlist.join(@newline)
270
270
  end
271
271
 
272
272
  s
273
273
  end
274
- private :context_diff
275
-
276
- def ed_diff(format, _last = false)
277
- warn "Expecting only one block in an old diff hunk!" if @blocks.size > 1
278
-
279
- s =
280
- if format == :reverse_ed
281
- encode("#{ED_DIFF_OP_ACTION[@blocks[0].op]}#{context_range(:old, ",")}\n")
282
- else
283
- encode("#{context_range(:old, " ")}#{ED_DIFF_OP_ACTION[@blocks[0].op]}\n")
284
- end
285
274
 
286
- unless @blocks[0].insert.empty?
287
- @data_new[@start_new..@end_new].each do |e|
288
- s << e.chomp + encode("\n")
289
- end
290
- s << encode(".\n")
291
- end
292
- s
293
- end
294
- private :ed_diff
295
-
296
- # Generate a range of item numbers to print. Only print 1 number if the
297
- # range has only one item in it. Otherwise, it's 'start,end'
298
- def context_range(mode, op, last = false)
275
+ # Generate a range of item numbers to print. Only print 1 number if the range has only
276
+ # one item in it. Otherwise, it's 'start,end'
277
+ def context_range(mode, op)
299
278
  case mode
300
279
  when :old
301
280
  s, e = (@start_old + 1), (@end_old + 1)
@@ -303,61 +282,35 @@ class Diff::LCS::Hunk
303
282
  s, e = (@start_new + 1), (@end_new + 1)
304
283
  end
305
284
 
306
- e -= 1 if last
307
- e = 1 if e.zero?
308
-
309
285
  (s < e) ? "#{s}#{op}#{e}" : e.to_s
310
286
  end
311
- private :context_range
312
287
 
313
- # Generate a range of item numbers to print for unified diff. Print number
314
- # where block starts, followed by number of lines in the block
315
- # (don't print number of lines if it's 1)
316
- def unified_range(mode, last)
317
- case mode
318
- when :old
319
- s, e = (@start_old + 1), (@end_old + 1)
320
- when :new
321
- s, e = (@start_new + 1), (@end_new + 1)
322
- end
288
+ # Generate a range of item numbers to print for unified diff. Print number where block
289
+ # starts, followed by number of lines in the block (don't print number of lines if it's
290
+ # 1)
291
+ def unified_range(mode)
292
+ s, e =
293
+ case mode
294
+ when :old
295
+ return "0,0" if @old_empty
296
+ [(@start_old + 1), (@end_old + 1)]
297
+ when :new
298
+ return "0,0" if @new_empty
299
+ [(@start_new + 1), (@end_new + 1)]
300
+ end
323
301
 
324
- length = e - s + (last ? 0 : 1)
302
+ length = e - s + 1
325
303
 
326
- first = (length < 2) ? e : s # "strange, but correct"
327
- (length <= 1) ? first.to_s : "#{first},#{length}"
304
+ (length <= 1) ? e.to_s : "#{s},#{length}"
328
305
  end
329
- private :unified_range
330
306
 
331
307
  def missing_last_newline?(data)
332
- newline = encode("\n")
333
-
334
308
  if data[-2]
335
- data[-2].end_with?(newline) && !data[-1].end_with?(newline)
309
+ data[-2].end_with?(@newline) && !data[-1].end_with?(@newline)
336
310
  elsif data[-1]
337
- !data[-1].end_with?(newline)
311
+ !data[-1].end_with?(@newline)
338
312
  else
339
313
  true
340
314
  end
341
315
  end
342
-
343
- if String.method_defined?(:encoding)
344
- def encode(literal, target_encoding = @preferred_data_encoding)
345
- literal.encode target_encoding
346
- end
347
-
348
- def encode_as(string, *args)
349
- args.map { |arg| arg.encode(string.encoding) }
350
- end
351
- else
352
- def encode(literal, _target_encoding = nil)
353
- literal
354
- end
355
-
356
- def encode_as(_string, *args)
357
- args
358
- end
359
- end
360
-
361
- private :encode
362
- private :encode_as
363
316
  end