diff-lcs 1.4.1 → 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.
data/Manifest.txt CHANGED
@@ -6,7 +6,6 @@ License.md
6
6
  Manifest.txt
7
7
  README.rdoc
8
8
  Rakefile
9
- autotest/discover.rb
10
9
  bin/htmldiff
11
10
  bin/ldiff
12
11
  docs/COPYING.txt
@@ -34,6 +33,21 @@ spec/fixtures/ldiff/output.diff-c
34
33
  spec/fixtures/ldiff/output.diff-e
35
34
  spec/fixtures/ldiff/output.diff-f
36
35
  spec/fixtures/ldiff/output.diff-u
36
+ spec/fixtures/ldiff/output.diff.chef
37
+ spec/fixtures/ldiff/output.diff.chef-c
38
+ spec/fixtures/ldiff/output.diff.chef-e
39
+ spec/fixtures/ldiff/output.diff.chef-f
40
+ spec/fixtures/ldiff/output.diff.chef-u
41
+ spec/fixtures/ldiff/output.diff.chef2
42
+ spec/fixtures/ldiff/output.diff.chef2-c
43
+ spec/fixtures/ldiff/output.diff.chef2-d
44
+ spec/fixtures/ldiff/output.diff.chef2-e
45
+ spec/fixtures/ldiff/output.diff.chef2-f
46
+ spec/fixtures/ldiff/output.diff.chef2-u
47
+ spec/fixtures/new-chef
48
+ spec/fixtures/new-chef2
49
+ spec/fixtures/old-chef
50
+ spec/fixtures/old-chef2
37
51
  spec/hunk_spec.rb
38
52
  spec/issues_spec.rb
39
53
  spec/lcs_spec.rb
data/README.rdoc CHANGED
@@ -12,14 +12,15 @@ Diff::LCS computes the difference between two Enumerable sequences using the
12
12
  McIlroy-Hunt longest common subsequence (LCS) algorithm. It includes utilities
13
13
  to create a simple HTML diff output format and a standard diff-like tool.
14
14
 
15
- This is release 1.4, providing a simple extension that allows for
16
- Diff::LCS::Change objects to be treated implicitly as arrays. Ruby versions
17
- below 2.5 are soft-deprecated.
18
-
19
- This means that older versions are no longer part of the CI test suite. If any
20
- changes have been introduced that break those versions, bug reports and patches
21
- will be accepted, but it will be up to the reporter to verify any fixes prior
22
- to release. A future release will completely break compatibility.
15
+ This is release 1.4.3, providing a simple extension that allows for
16
+ Diff::LCS::Change objects to be treated implicitly as arrays and fixes a
17
+ number of formatting issues.
18
+
19
+ Ruby versions below 2.5 are soft-deprecated, which means that older versions
20
+ are no longer part of the CI test suite. If any changes have been introduced
21
+ that break those versions, bug reports and patches will be accepted, but it
22
+ will be up to the reporter to verify any fixes prior to release. The next
23
+ major release will completely break compatibility.
23
24
 
24
25
  == Synopsis
25
26
 
data/Rakefile CHANGED
@@ -2,14 +2,68 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'rspec'
5
+ require 'rspec/core/rake_task'
5
6
  require 'hoe'
6
7
 
8
+ # This is required until https://github.com/seattlerb/hoe/issues/112 is fixed
9
+ class Hoe
10
+ def with_config
11
+ config = Hoe::DEFAULT_CONFIG
12
+
13
+ rc = File.expand_path("~/.hoerc")
14
+ homeconfig = load_config(rc)
15
+ config = config.merge(homeconfig)
16
+
17
+ localconfig = load_config(File.expand_path(File.join(Dir.pwd, ".hoerc")))
18
+ config = config.merge(localconfig)
19
+
20
+ yield config, rc
21
+ end
22
+
23
+ def load_config(name)
24
+ File.exist?(name) ? safe_load_yaml(name) : {}
25
+ end
26
+
27
+ def safe_load_yaml(name)
28
+ return safe_load_yaml_file(name) if YAML.respond_to?(:safe_load_file)
29
+
30
+ data = IO.binread(name)
31
+ YAML.safe_load(data, permitted_classes: [Regexp])
32
+ rescue
33
+ YAML.safe_load(data, [Regexp])
34
+ end
35
+
36
+ def safe_load_yaml_file(name)
37
+ YAML.safe_load_file(name, permitted_classes: [Regexp])
38
+ rescue
39
+ YAML.safe_load_file(name, [Regexp])
40
+ end
41
+ end
42
+
7
43
  Hoe.plugin :bundler
8
44
  Hoe.plugin :doofus
9
- Hoe.plugin :email unless ENV['CI'] or ENV['TRAVIS']
10
45
  Hoe.plugin :gemspec2
11
46
  Hoe.plugin :git
12
- Hoe.plugin :travis
47
+
48
+ if RUBY_VERSION < '1.9'
49
+ class Array #:nodoc:
50
+ def to_h
51
+ Hash[*flatten(1)]
52
+ end
53
+ end
54
+
55
+ class Gem::Specification #:nodoc:
56
+ def metadata=(*); end
57
+
58
+ def default_value(*); end
59
+ end
60
+
61
+ class Object #:nodoc:
62
+ def caller_locations(*)
63
+ []
64
+ end
65
+ end
66
+ end
13
67
 
14
68
  _spec = Hoe.spec 'diff-lcs' do
15
69
  developer('Austin Ziegler', 'halostatue@gmail.com')
@@ -26,9 +80,20 @@ _spec = Hoe.spec 'diff-lcs' do
26
80
  extra_dev_deps << ['hoe-rubygems', '~> 1.0']
27
81
  extra_dev_deps << ['rspec', '>= 2.0', '< 4']
28
82
  extra_dev_deps << ['rake', '>= 10.0', '< 14']
29
- extra_dev_deps << ['rdoc', '>= 0']
83
+ extra_dev_deps << ['rdoc', '>= 6.3.1', '< 7']
84
+ end
85
+
86
+ desc "Run all specifications"
87
+ RSpec::Core::RakeTask.new(:spec) do |t|
88
+ rspec_dirs = %w(spec lib).join(":")
89
+ t.rspec_opts = ["-I#{rspec_dirs}"]
30
90
  end
31
91
 
92
+ Rake::Task["spec"].actions.uniq! { |a| a.source_location }
93
+
94
+ task :default => :spec unless Rake::Task["default"].prereqs.include?("spec")
95
+ task :test => :spec unless Rake::Task["test"].prereqs.include?("spec")
96
+
32
97
  if RUBY_VERSION >= '2.0' && RUBY_ENGINE == 'ruby'
33
98
  namespace :spec do
34
99
  desc "Runs test coverage. Only works Ruby 2.0+ and assumes 'simplecov' is installed."
@@ -38,3 +103,19 @@ if RUBY_VERSION >= '2.0' && RUBY_ENGINE == 'ruby'
38
103
  end
39
104
  end
40
105
  end
106
+
107
+ task :ruby18 do
108
+ puts <<-MESSAGE
109
+ You are starting a barebones Ruby 1.8 docker environment. You will need to
110
+ do the following:
111
+
112
+ - mv Gemfile.lock{,.v2}
113
+ - gem install bundler --version 1.17.2 --no-ri --no-rdoc
114
+ - ruby -S bundle
115
+ - rake
116
+
117
+ Don't forget to restore your Gemfile.lock after testing.
118
+
119
+ MESSAGE
120
+ sh "docker run -it --rm -v #{Dir.pwd}:/root/diff-lcs bellbind/docker-ruby18-rails2 bash -l"
121
+ end
@@ -3,7 +3,7 @@
3
3
  unless 0.respond_to?(:positive?)
4
4
  class Fixnum # rubocop:disable Lint/UnifiedInteger, Style/Documentation
5
5
  def positive?
6
- self > 0 # rubocop:disable Styel/NumericPredicate
6
+ self > 0 # rubocop:disable Style/NumericPredicate
7
7
  end
8
8
  end
9
9
  end
@@ -19,7 +19,7 @@ class Diff::LCS::Block
19
19
  end
20
20
 
21
21
  def diff_size
22
- (@insert.size - @remove.size).abs
22
+ @insert.size - @remove.size
23
23
  end
24
24
 
25
25
  def op
data/lib/diff/lcs/hunk.rb CHANGED
@@ -2,30 +2,42 @@
2
2
 
3
3
  require 'diff/lcs/block'
4
4
 
5
- # A Hunk is a group of Blocks which overlap because of the context
6
- # surrounding each block. (So if we're not using context, every hunk will
7
- # contain one block.) Used in the diff program (bin/diff).
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).
8
8
  class Diff::LCS::Hunk
9
- # Create a hunk using references to both the old and new data, as well as
10
- # the piece of data.
9
+ OLD_DIFF_OP_ACTION = { '+' => 'a', '-' => 'd', '!' => 'c' }.freeze #:nodoc:
10
+ ED_DIFF_OP_ACTION = { '+' => 'a', '-' => 'd', '!' => 'c' }.freeze #:nodoc:
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.
11
16
  def initialize(data_old, data_new, piece, flag_context, file_length_difference)
12
17
  # At first, a hunk will have just one Block in it
13
18
  @blocks = [Diff::LCS::Block.new(piece)]
19
+
20
+ if @blocks[0].remove.empty? && @blocks[0].insert.empty?
21
+ fail "Cannot build a hunk from #{piece.inspect}; has no add or remove actions"
22
+ end
23
+
14
24
  if String.method_defined?(:encoding)
15
25
  @preferred_data_encoding = data_old.fetch(0, data_new.fetch(0, '')).encoding
16
26
  end
27
+
17
28
  @data_old = data_old
18
29
  @data_new = data_new
19
30
 
20
31
  before = after = file_length_difference
21
32
  after += @blocks[0].diff_size
22
33
  @file_length_difference = after # The caller must get this manually
23
- @max_diff_size = @blocks.lazy.map { |e| e.diff_size }.max
34
+ @max_diff_size = @blocks.map { |e| e.diff_size.abs }.max
35
+
24
36
 
25
37
  # Save the start & end of each array. If the array doesn't exist (e.g.,
26
- # we're only adding items in this block), then figure out the line
27
- # number based on the line number of the other file and the current
28
- # difference in file lengths.
38
+ # we're only adding items in this block), then figure out the line number
39
+ # based on the line number of the other file and the current difference in
40
+ # file lengths.
29
41
  if @blocks[0].remove.empty?
30
42
  a1 = a2 = nil
31
43
  else
@@ -55,23 +67,26 @@ class Diff::LCS::Hunk
55
67
 
56
68
  # Change the "start" and "end" fields to note that context should be added
57
69
  # to this hunk.
58
- attr_accessor :flag_context
70
+ attr_accessor :flag_context # rubocop:disable Layout/EmptyLinesAroundAttributeAccessor
59
71
  undef :flag_context=
60
72
  def flag_context=(context) #:nodoc: # rubocop:disable Lint/DuplicateMethods
61
73
  return if context.nil? or context.zero?
62
74
 
63
75
  add_start = context > @start_old ? @start_old : context
76
+
64
77
  @start_old -= add_start
65
78
  @start_new -= add_start
66
79
 
80
+ old_size = @data_old.size
81
+
67
82
  add_end =
68
- if (@end_old + context) > @data_old.size
69
- @data_old.size - @end_old
83
+ if (@end_old + context) > old_size
84
+ old_size - @end_old
70
85
  else
71
86
  context
72
87
  end
73
88
 
74
- add_end = @max_diff_size if add_end > @max_diff_size
89
+ add_end = @max_diff_size if add_end >= old_size
75
90
 
76
91
  @end_old += add_end
77
92
  @end_new += add_end
@@ -98,18 +113,18 @@ class Diff::LCS::Hunk
98
113
  end
99
114
 
100
115
  # Returns a diff string based on a format.
101
- def diff(format)
116
+ def diff(format, last = false)
102
117
  case format
103
118
  when :old
104
- old_diff
119
+ old_diff(last)
105
120
  when :unified
106
- unified_diff
121
+ unified_diff(last)
107
122
  when :context
108
- context_diff
123
+ context_diff(last)
109
124
  when :ed
110
125
  self
111
126
  when :reverse_ed, :ed_finish
112
- ed_diff(format)
127
+ ed_diff(format, last)
113
128
  else
114
129
  fail "Unknown diff format #{format}."
115
130
  end
@@ -117,35 +132,34 @@ class Diff::LCS::Hunk
117
132
 
118
133
  # Note that an old diff can't have any context. Therefore, we know that
119
134
  # there's only one block in the hunk.
120
- def old_diff
135
+ def old_diff(_last = false)
121
136
  warn 'Expecting only one block in an old diff hunk!' if @blocks.size > 1
122
- op_act = { '+' => 'a', '-' => 'd', '!' => 'c' }
123
137
 
124
138
  block = @blocks[0]
125
139
 
126
140
  # Calculate item number range. Old diff range is just like a context
127
141
  # diff range, except the ranges are on one line with the action between
128
142
  # them.
129
- s = encode("#{context_range(:old)}#{op_act[block.op]}#{context_range(:new)}\n")
143
+ s = encode("#{context_range(:old, ',')}#{OLD_DIFF_OP_ACTION[block.op]}#{context_range(:new, ',')}\n")
130
144
  # If removing anything, just print out all the remove lines in the hunk
131
145
  # which is just all the remove lines in the block.
132
146
  unless block.remove.empty?
133
- @data_old[@start_old..@end_old].each { |e| s << encode('< ') + e + encode("\n") }
147
+ @data_old[@start_old..@end_old].each { |e| s << encode('< ') + e.chomp + encode("\n") }
134
148
  end
135
149
 
136
150
  s << encode("---\n") if block.op == '!'
137
151
 
138
152
  unless block.insert.empty?
139
- @data_new[@start_new..@end_new].each { |e| s << encode('> ') + e + encode("\n") }
153
+ @data_new[@start_new..@end_new].each { |e| s << encode('> ') + e.chomp + encode("\n") }
140
154
  end
141
155
 
142
156
  s
143
157
  end
144
158
  private :old_diff
145
159
 
146
- def unified_diff
160
+ def unified_diff(last = false)
147
161
  # Calculate item number range.
148
- s = encode("@@ -#{unified_range(:old)} +#{unified_range(:new)} @@\n")
162
+ s = encode("@@ -#{unified_range(:old, last)} +#{unified_range(:new, last)} @@\n")
149
163
 
150
164
  # Outlist starts containing the hunk of the old file. Removing an item
151
165
  # just means putting a '-' in front of it. Inserting an item requires
@@ -158,7 +172,14 @@ class Diff::LCS::Hunk
158
172
  # file -- don't take removed items into account.
159
173
  lo, hi, num_added, num_removed = @start_old, @end_old, 0, 0
160
174
 
161
- outlist = @data_old[lo..hi].map { |e| e.insert(0, encode(' ')) }
175
+ outlist = @data_old[lo..hi].map { |e| String.new("#{encode(' ')}#{e.chomp}") }
176
+
177
+ last_block = blocks[-1]
178
+
179
+ if last
180
+ old_missing_newline = missing_last_newline?(@data_old)
181
+ new_missing_newline = missing_last_newline?(@data_new)
182
+ end
162
183
 
163
184
  @blocks.each do |block|
164
185
  block.remove.each do |item|
@@ -167,67 +188,100 @@ class Diff::LCS::Hunk
167
188
  outlist[offset][0, 1] = encode(op)
168
189
  num_removed += 1
169
190
  end
191
+
192
+ if last && block == last_block && old_missing_newline && !new_missing_newline
193
+ outlist << encode('\')
194
+ num_removed += 1
195
+ end
196
+
170
197
  block.insert.each do |item|
171
198
  op = item.action.to_s # +
172
199
  offset = item.position - @start_new + num_removed
173
- outlist[offset, 0] = encode(op) + @data_new[item.position]
200
+ outlist[offset, 0] = encode(op) + @data_new[item.position].chomp
174
201
  num_added += 1
175
202
  end
176
203
  end
177
204
 
205
+ outlist << encode('\') if last && new_missing_newline
206
+
178
207
  s << outlist.join(encode("\n"))
208
+
209
+ s
179
210
  end
180
211
  private :unified_diff
181
212
 
182
- def context_diff
213
+ def context_diff(last = false)
183
214
  s = encode("***************\n")
184
- s << encode("*** #{context_range(:old)} ****\n")
185
- r = context_range(:new)
215
+ s << encode("*** #{context_range(:old, ',', last)} ****\n")
216
+ r = context_range(:new, ',', last)
217
+
218
+ if last
219
+ old_missing_newline = missing_last_newline?(@data_old)
220
+ new_missing_newline = missing_last_newline?(@data_new)
221
+ end
186
222
 
187
223
  # Print out file 1 part for each block in context diff format if there
188
224
  # are any blocks that remove items
189
225
  lo, hi = @start_old, @end_old
190
226
  removes = @blocks.reject { |e| e.remove.empty? }
191
- if removes
192
- outlist = @data_old[lo..hi].map { |e| e.insert(0, encode(' ')) }
227
+
228
+ unless removes.empty?
229
+ outlist = @data_old[lo..hi].map { |e| String.new("#{encode(' ')}#{e.chomp}") }
230
+
231
+ last_block = removes[-1]
193
232
 
194
233
  removes.each do |block|
195
234
  block.remove.each do |item|
196
- outlist[item.position - lo].insert(0, encode(block.op)) # - or !
235
+ outlist[item.position - lo][0, 1] = encode(block.op) # - or !
236
+ end
237
+
238
+ if last && block == last_block && old_missing_newline
239
+ outlist << encode('\')
197
240
  end
198
241
  end
199
- s << outlist.join("\n")
242
+
243
+ s << outlist.join(encode("\n")) << encode("\n")
200
244
  end
201
245
 
202
- s << encode("\n--- #{r} ----\n")
246
+ s << encode("--- #{r} ----\n")
203
247
  lo, hi = @start_new, @end_new
204
248
  inserts = @blocks.reject { |e| e.insert.empty? }
205
- if inserts
206
- outlist = @data_new[lo..hi].collect { |e| e.insert(0, encode(' ')) }
249
+
250
+ unless inserts.empty?
251
+ outlist = @data_new[lo..hi].map { |e| String.new("#{encode(' ')}#{e.chomp}") }
252
+
253
+ last_block = inserts[-1]
254
+
207
255
  inserts.each do |block|
208
256
  block.insert.each do |item|
209
- outlist[item.position - lo].insert(0, encode(block.op)) # - or !
257
+ outlist[item.position - lo][0, 1] = encode(block.op) # + or !
258
+ end
259
+
260
+ if last && block == last_block && new_missing_newline
261
+ outlist << encode('\')
210
262
  end
211
263
  end
212
- s << outlist.join("\n")
264
+ s << outlist.join(encode("\n"))
213
265
  end
266
+
214
267
  s
215
268
  end
216
269
  private :context_diff
217
270
 
218
- def ed_diff(format)
219
- op_act = { '+' => 'a', '-' => 'd', '!' => 'c' }
271
+ def ed_diff(format, _last = false)
220
272
  warn 'Expecting only one block in an old diff hunk!' if @blocks.size > 1
221
273
 
222
274
  s =
223
275
  if format == :reverse_ed
224
- encode("#{op_act[@blocks[0].op]}#{context_range(:old)}\n")
276
+ encode("#{ED_DIFF_OP_ACTION[@blocks[0].op]}#{context_range(:old, ',')}\n")
225
277
  else
226
- encode("#{context_range(:old, ' ')}#{op_act[@blocks[0].op]}\n")
278
+ encode("#{context_range(:old, ' ')}#{ED_DIFF_OP_ACTION[@blocks[0].op]}\n")
227
279
  end
228
280
 
229
281
  unless @blocks[0].insert.empty?
230
- @data_new[@start_new..@end_new].each do |e| s << e + encode("\n") end
282
+ @data_new[@start_new..@end_new].each do |e|
283
+ s << e.chomp + encode("\n")
284
+ end
231
285
  s << encode(".\n")
232
286
  end
233
287
  s
@@ -236,7 +290,7 @@ class Diff::LCS::Hunk
236
290
 
237
291
  # Generate a range of item numbers to print. Only print 1 number if the
238
292
  # range has only one item in it. Otherwise, it's 'start,end'
239
- def context_range(mode, op = ',') # rubocop:disable Naming/UncommunicativeMethodParamName
293
+ def context_range(mode, op, last = false)
240
294
  case mode
241
295
  when :old
242
296
  s, e = (@start_old + 1), (@end_old + 1)
@@ -244,6 +298,9 @@ class Diff::LCS::Hunk
244
298
  s, e = (@start_new + 1), (@end_new + 1)
245
299
  end
246
300
 
301
+ e -= 1 if last
302
+ e = 1 if e.zero?
303
+
247
304
  s < e ? "#{s}#{op}#{e}" : e.to_s
248
305
  end
249
306
  private :context_range
@@ -251,7 +308,7 @@ class Diff::LCS::Hunk
251
308
  # Generate a range of item numbers to print for unified diff. Print number
252
309
  # where block starts, followed by number of lines in the block
253
310
  # (don't print number of lines if it's 1)
254
- def unified_range(mode)
311
+ def unified_range(mode, last)
255
312
  case mode
256
313
  when :old
257
314
  s, e = (@start_old + 1), (@end_old + 1)
@@ -259,12 +316,25 @@ class Diff::LCS::Hunk
259
316
  s, e = (@start_new + 1), (@end_new + 1)
260
317
  end
261
318
 
262
- length = e - s + 1
319
+ length = e - s + (last ? 0 : 1)
320
+
263
321
  first = length < 2 ? e : s # "strange, but correct"
264
- length == 1 ? first.to_s : "#{first},#{length}"
322
+ length <= 1 ? first.to_s : "#{first},#{length}"
265
323
  end
266
324
  private :unified_range
267
325
 
326
+ def missing_last_newline?(data)
327
+ newline = encode("\n")
328
+
329
+ if data[-2]
330
+ data[-2].end_with?(newline) && !data[-1].end_with?(newline)
331
+ elsif data[-1]
332
+ !data[-1].end_with?(newline)
333
+ else
334
+ true
335
+ end
336
+ end
337
+
268
338
  if String.method_defined?(:encoding)
269
339
  def encode(literal, target_encoding = @preferred_data_encoding)
270
340
  literal.encode target_encoding
@@ -44,13 +44,12 @@ class << Diff::LCS::Internals
44
44
  b_finish = b.size - 1
45
45
  vector = []
46
46
 
47
- # Prune off any common elements at the beginning...
47
+ # Collect any common elements at the beginning...
48
48
  while (a_start <= a_finish) and (b_start <= b_finish) and (a[a_start] == b[b_start])
49
49
  vector[a_start] = b_start
50
50
  a_start += 1
51
51
  b_start += 1
52
52
  end
53
- b_start = a_start
54
53
 
55
54
  # Now the end...
56
55
  while (a_start <= a_finish) and (b_start <= b_finish) and (a[a_finish] == b[b_finish])
@@ -60,6 +59,7 @@ class << Diff::LCS::Internals
60
59
  end
61
60
 
62
61
  # Now, compute the equivalence classes of positions of elements.
62
+ # An explanation for how this works: https://codeforces.com/topic/92191
63
63
  b_matches = position_hash(b, b_start..b_finish)
64
64
 
65
65
  thresh = []
@@ -71,6 +71,10 @@ class << Diff::LCS::Internals
71
71
  bm = b_matches[ai]
72
72
  k = nil
73
73
  bm.reverse_each do |j|
74
+ # Although the threshold check is not mandatory for this to work,
75
+ # it may have an optimization purpose
76
+ # An attempt to remove it: https://github.com/halostatue/diff-lcs/pull/72
77
+ # Why it is reintroduced: https://github.com/halostatue/diff-lcs/issues/78
74
78
  if k and (thresh[k] > j) and (thresh[k - 1] < j)
75
79
  thresh[k] = j
76
80
  else
@@ -253,7 +257,7 @@ enumerable as either source or destination value."
253
257
  end
254
258
 
255
259
  # Binary search for the insertion point
256
- last_index ||= enum.size
260
+ last_index ||= enum.size - 1
257
261
  first_index = 0
258
262
  while first_index <= last_index
259
263
  i = (first_index + last_index) >> 1
@@ -98,24 +98,19 @@ class << Diff::LCS::Ldiff
98
98
  # items we've read from each file will differ by FLD (could be 0).
99
99
  file_length_difference = 0
100
100
 
101
- if @binary.nil? or @binary
102
- data_old = IO.read(file_old)
103
- data_new = IO.read(file_new)
104
-
105
- # Test binary status
106
- if @binary.nil?
107
- old_txt = data_old[0, 4096].scan(/\0/).empty?
108
- new_txt = data_new[0, 4096].scan(/\0/).empty?
109
- @binary = !old_txt or !new_txt
110
- end
101
+ data_old = IO.read(file_old)
102
+ data_new = IO.read(file_new)
103
+
104
+ # Test binary status
105
+ if @binary.nil?
106
+ old_txt = data_old[0, 4096].scan(/\0/).empty?
107
+ new_txt = data_new[0, 4096].scan(/\0/).empty?
108
+ @binary = !old_txt || !new_txt
109
+ end
111
110
 
112
- unless @binary
113
- data_old = data_old.split($/).map { |e| e.chomp }
114
- data_new = data_new.split($/).map { |e| e.chomp }
115
- end
116
- else
117
- data_old = IO.readlines(file_old).map { |e| e.chomp }
118
- data_new = IO.readlines(file_new).map { |e| e.chomp }
111
+ unless @binary
112
+ data_old = data_old.lines.to_a
113
+ data_new = data_new.lines.to_a
119
114
  end
120
115
 
121
116
  # diff yields lots of pieces, each of which is basically a Block object
@@ -150,20 +145,21 @@ class << Diff::LCS::Ldiff
150
145
  end
151
146
 
152
147
  diffs.each do |piece|
153
- begin
148
+ begin # rubocop:disable Style/RedundantBegin
154
149
  hunk = Diff::LCS::Hunk.new(data_old, data_new, piece, @lines, file_length_difference)
155
150
  file_length_difference = hunk.file_length_difference
156
151
 
157
152
  next unless oldhunk
158
153
  next if @lines.positive? and hunk.merge(oldhunk)
159
154
 
160
- output << oldhunk.diff(@format) << "\n"
155
+ output << oldhunk.diff(@format)
156
+ output << "\n" if @format == :unified
161
157
  ensure
162
158
  oldhunk = hunk
163
159
  end
164
160
  end
165
161
 
166
- last = oldhunk.diff(@format)
162
+ last = oldhunk.diff(@format, true)
167
163
  last << "\n" if last.respond_to?(:end_with?) && !last.end_with?("\n")
168
164
 
169
165
  output << last