diff-lcs 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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