diff-lcs 1.5.0 → 1.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +491 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +74 -0
- data/CONTRIBUTORS.md +48 -0
- data/Contributing.md +45 -90
- data/{License.md → LICENCE.md} +6 -4
- data/Manifest.txt +7 -4
- data/README.md +92 -0
- data/Rakefile +43 -66
- data/SECURITY.md +41 -0
- data/bin/htmldiff +4 -4
- data/docs/artistic.txt +1 -1
- data/lib/diff/lcs/array.rb +1 -1
- data/lib/diff/lcs/backports.rb +2 -2
- data/lib/diff/lcs/block.rb +4 -4
- data/lib/diff/lcs/callbacks.rb +9 -7
- data/lib/diff/lcs/change.rb +20 -20
- data/lib/diff/lcs/htmldiff.rb +26 -16
- data/lib/diff/lcs/hunk.rb +66 -45
- data/lib/diff/lcs/internals.rb +17 -17
- data/lib/diff/lcs/ldiff.rb +86 -74
- data/lib/diff/lcs.rb +66 -63
- data/lib/diff-lcs.rb +1 -1
- data/spec/change_spec.rb +50 -50
- data/spec/diff_spec.rb +14 -14
- data/spec/hunk_spec.rb +20 -20
- data/spec/issues_spec.rb +76 -70
- data/spec/lcs_spec.rb +11 -11
- data/spec/ldiff_spec.rb +30 -17
- data/spec/patch_spec.rb +84 -84
- data/spec/sdiff_spec.rb +111 -109
- data/spec/spec_helper.rb +76 -74
- data/spec/traverse_balanced_spec.rb +191 -189
- data/spec/traverse_sequences_spec.rb +31 -31
- metadata +55 -30
- data/Code-of-Conduct.md +0 -74
- data/History.md +0 -400
- data/README.rdoc +0 -84
data/lib/diff/lcs.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Diff; end unless defined? Diff
|
3
|
+
module Diff; end unless defined? Diff
|
4
4
|
|
5
5
|
# == How Diff Works (by Mark-Jason Dominus)
|
6
6
|
#
|
@@ -49,25 +49,26 @@ module Diff; end unless defined? Diff # rubocop:disable Style/Documentation
|
|
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 =
|
52
|
+
VERSION = "1.6.0"
|
53
53
|
end
|
54
54
|
|
55
|
-
require
|
56
|
-
require
|
55
|
+
require "diff/lcs/callbacks"
|
56
|
+
require "diff/lcs/internals"
|
57
57
|
|
58
|
-
module Diff::LCS
|
58
|
+
module Diff::LCS
|
59
59
|
# Returns an Array containing the longest common subsequence(s) between
|
60
60
|
# +self+ and +other+. See Diff::LCS#lcs.
|
61
61
|
#
|
62
62
|
# lcs = seq1.lcs(seq2)
|
63
63
|
#
|
64
64
|
# A note when using objects: Diff::LCS only works properly when each object
|
65
|
-
# can be used as a key in a Hash
|
66
|
-
#
|
67
|
-
# identically for key purposes. That is:
|
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
68
|
#
|
69
|
-
# O.new('a').eql?(O.new('a')) == true
|
70
|
-
|
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
|
71
72
|
Diff::LCS.lcs(self, other, &block)
|
72
73
|
end
|
73
74
|
|
@@ -101,7 +102,7 @@ module Diff::LCS # rubocop:disable Style/Documentation
|
|
101
102
|
def patch(patchset)
|
102
103
|
Diff::LCS.patch(self, patchset)
|
103
104
|
end
|
104
|
-
|
105
|
+
alias_method :unpatch, :patch
|
105
106
|
|
106
107
|
# Attempts to patch +self+ with the provided +patchset+. A new sequence based
|
107
108
|
# on +self+ and the +patchset+ will be created. See Diff::LCS#patch. Does no
|
@@ -141,11 +142,11 @@ module Diff::LCS # rubocop:disable Style/Documentation
|
|
141
142
|
end
|
142
143
|
|
143
144
|
class << Diff::LCS
|
144
|
-
def lcs(seq1, seq2, &block)
|
145
|
+
def lcs(seq1, seq2, &block) # :yields: seq1[i] for each matched
|
145
146
|
matches = Diff::LCS::Internals.lcs(seq1, seq2)
|
146
147
|
ret = []
|
147
|
-
string = seq1.
|
148
|
-
matches.
|
148
|
+
string = seq1.is_a? String
|
149
|
+
matches.each_index do |i|
|
149
150
|
next if matches[i].nil?
|
150
151
|
|
151
152
|
v = string ? seq1[i, 1] : seq1[i]
|
@@ -154,7 +155,7 @@ class << Diff::LCS
|
|
154
155
|
end
|
155
156
|
ret
|
156
157
|
end
|
157
|
-
|
158
|
+
alias_method :LCS, :lcs
|
158
159
|
|
159
160
|
# #diff computes the smallest set of additions and deletions necessary to
|
160
161
|
# turn the first sequence into the second, and returns a description of these
|
@@ -165,7 +166,7 @@ class << Diff::LCS
|
|
165
166
|
# Class argument is provided for +callbacks+, #diff will attempt to
|
166
167
|
# initialise it. If the +callbacks+ object (possibly initialised) responds to
|
167
168
|
# #finish, it will be called.
|
168
|
-
def diff(seq1, seq2, callbacks = nil, &block) # :yields diff changes
|
169
|
+
def diff(seq1, seq2, callbacks = nil, &block) # :yields: diff changes
|
169
170
|
diff_traversal(:diff, seq1, seq2, callbacks || Diff::LCS::DiffCallbacks, &block)
|
170
171
|
end
|
171
172
|
|
@@ -197,7 +198,7 @@ class << Diff::LCS
|
|
197
198
|
# # insert
|
198
199
|
# end
|
199
200
|
# end
|
200
|
-
def sdiff(seq1, seq2, callbacks = nil, &block)
|
201
|
+
def sdiff(seq1, seq2, callbacks = nil, &block) # :yields: diff changes
|
201
202
|
diff_traversal(:sdiff, seq1, seq2, callbacks || Diff::LCS::SDiffCallbacks, &block)
|
202
203
|
end
|
203
204
|
|
@@ -256,7 +257,7 @@ class << Diff::LCS
|
|
256
257
|
#
|
257
258
|
# The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>, and
|
258
259
|
# <tt>callbacks#discard_b</tt> are invoked with an event comprising the
|
259
|
-
# action ("=", "+", or "-", respectively), the
|
260
|
+
# action ("=", "+", or "-", respectively), the indexes +i+ and +j+, and the
|
260
261
|
# elements <tt>A[i]</tt> and <tt>B[j]</tt>. Return values are discarded by
|
261
262
|
# #traverse_sequences.
|
262
263
|
#
|
@@ -282,12 +283,12 @@ class << Diff::LCS
|
|
282
283
|
# <tt>callbacks#discard_b</tt> will be called after the end of the sequence
|
283
284
|
# is reached, if +a+ has not yet reached the end of +A+ or +b+ has not yet
|
284
285
|
# reached the end of +B+.
|
285
|
-
def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks)
|
286
|
+
def traverse_sequences(seq1, seq2, callbacks = Diff::LCS::SequenceCallbacks) # :yields: change events
|
286
287
|
callbacks ||= Diff::LCS::SequenceCallbacks
|
287
288
|
matches = Diff::LCS::Internals.lcs(seq1, seq2)
|
288
289
|
|
289
290
|
run_finished_a = run_finished_b = false
|
290
|
-
string = seq1.
|
291
|
+
string = seq1.is_a?(String)
|
291
292
|
|
292
293
|
a_size = seq1.size
|
293
294
|
b_size = seq2.size
|
@@ -299,7 +300,7 @@ class << Diff::LCS
|
|
299
300
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
300
301
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
301
302
|
|
302
|
-
event = Diff::LCS::ContextChange.new(
|
303
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
303
304
|
event = yield event if block_given?
|
304
305
|
callbacks.discard_a(event)
|
305
306
|
end
|
@@ -310,13 +311,13 @@ class << Diff::LCS
|
|
310
311
|
break unless bj < b_line
|
311
312
|
|
312
313
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
313
|
-
event = Diff::LCS::ContextChange.new(
|
314
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
314
315
|
event = yield event if block_given?
|
315
316
|
callbacks.discard_b(event)
|
316
317
|
bj += 1
|
317
318
|
end
|
318
319
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
319
|
-
event = Diff::LCS::ContextChange.new(
|
320
|
+
event = Diff::LCS::ContextChange.new("=", ai, ax, bj, bx)
|
320
321
|
event = yield event if block_given?
|
321
322
|
callbacks.match(event)
|
322
323
|
bj += 1
|
@@ -326,13 +327,13 @@ class << Diff::LCS
|
|
326
327
|
|
327
328
|
# The last entry (if any) processed was a match. +ai+ and +bj+ point just
|
328
329
|
# past the last matching lines in their sequences.
|
329
|
-
while (ai < a_size)
|
330
|
+
while (ai < a_size) || (bj < b_size)
|
330
331
|
# last A?
|
331
|
-
if ai == a_size
|
332
|
-
if callbacks.respond_to?(:finished_a)
|
332
|
+
if ai == a_size && bj < b_size
|
333
|
+
if callbacks.respond_to?(:finished_a) && !run_finished_a
|
333
334
|
ax = string ? seq1[-1, 1] : seq1[-1]
|
334
335
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
335
|
-
event = Diff::LCS::ContextChange.new(
|
336
|
+
event = Diff::LCS::ContextChange.new(">", (a_size - 1), ax, bj, bx)
|
336
337
|
event = yield event if block_given?
|
337
338
|
callbacks.finished_a(event)
|
338
339
|
run_finished_a = true
|
@@ -340,7 +341,7 @@ class << Diff::LCS
|
|
340
341
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
341
342
|
loop do
|
342
343
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
343
|
-
event = Diff::LCS::ContextChange.new(
|
344
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
344
345
|
event = yield event if block_given?
|
345
346
|
callbacks.discard_b(event)
|
346
347
|
bj += 1
|
@@ -350,11 +351,11 @@ class << Diff::LCS
|
|
350
351
|
end
|
351
352
|
|
352
353
|
# last B?
|
353
|
-
if bj == b_size
|
354
|
-
if callbacks.respond_to?(:finished_b)
|
354
|
+
if bj == b_size && ai < a_size
|
355
|
+
if callbacks.respond_to?(:finished_b) && !run_finished_b
|
355
356
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
356
357
|
bx = string ? seq2[-1, 1] : seq2[-1]
|
357
|
-
event = Diff::LCS::ContextChange.new(
|
358
|
+
event = Diff::LCS::ContextChange.new("<", ai, ax, (b_size - 1), bx)
|
358
359
|
event = yield event if block_given?
|
359
360
|
callbacks.finished_b(event)
|
360
361
|
run_finished_b = true
|
@@ -362,7 +363,7 @@ class << Diff::LCS
|
|
362
363
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
363
364
|
loop do
|
364
365
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
365
|
-
event = Diff::LCS::ContextChange.new(
|
366
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
366
367
|
event = yield event if block_given?
|
367
368
|
callbacks.discard_a(event)
|
368
369
|
ai += 1
|
@@ -374,7 +375,7 @@ class << Diff::LCS
|
|
374
375
|
if ai < a_size
|
375
376
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
376
377
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
377
|
-
event = Diff::LCS::ContextChange.new(
|
378
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
378
379
|
event = yield event if block_given?
|
379
380
|
callbacks.discard_a(event)
|
380
381
|
ai += 1
|
@@ -383,7 +384,7 @@ class << Diff::LCS
|
|
383
384
|
if bj < b_size
|
384
385
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
385
386
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
386
|
-
event = Diff::LCS::ContextChange.new(
|
387
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
387
388
|
event = yield event if block_given?
|
388
389
|
callbacks.discard_b(event)
|
389
390
|
bj += 1
|
@@ -421,7 +422,7 @@ class << Diff::LCS
|
|
421
422
|
# occurred.
|
422
423
|
#
|
423
424
|
# #traverse_balanced might be a bit slower than #traverse_sequences,
|
424
|
-
#
|
425
|
+
# noticeable only while processing huge amounts of data.
|
425
426
|
#
|
426
427
|
# == Algorithm
|
427
428
|
#
|
@@ -465,7 +466,7 @@ class << Diff::LCS
|
|
465
466
|
# The methods for <tt>callbacks#match</tt>, <tt>callbacks#discard_a</tt>,
|
466
467
|
# <tt>callbacks#discard_b</tt>, and <tt>callbacks#change</tt> are invoked
|
467
468
|
# with an event comprising the action ("=", "+", "-", or "!", respectively),
|
468
|
-
# the
|
469
|
+
# the indexes +i+ and +j+, and the elements <tt>A[i]</tt> and <tt>B[j]</tt>.
|
469
470
|
# Return values are discarded by #traverse_balanced.
|
470
471
|
#
|
471
472
|
# === Context
|
@@ -478,14 +479,14 @@ class << Diff::LCS
|
|
478
479
|
b_size = seq2.size
|
479
480
|
ai = bj = mb = 0
|
480
481
|
ma = -1
|
481
|
-
string = seq1.
|
482
|
+
string = seq1.is_a?(String)
|
482
483
|
|
483
484
|
# Process all the lines in the match vector.
|
484
485
|
loop do
|
485
|
-
# Find next match
|
486
|
+
# Find next match indexes +ma+ and +mb+
|
486
487
|
loop do
|
487
488
|
ma += 1
|
488
|
-
break unless ma < matches.size
|
489
|
+
break unless ma < matches.size && matches[ma].nil?
|
489
490
|
end
|
490
491
|
|
491
492
|
break if ma >= matches.size # end of matches?
|
@@ -493,36 +494,36 @@ class << Diff::LCS
|
|
493
494
|
mb = matches[ma]
|
494
495
|
|
495
496
|
# Change(seq2)
|
496
|
-
while (ai < ma)
|
497
|
+
while (ai < ma) || (bj < mb)
|
497
498
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
498
499
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
499
500
|
|
500
501
|
case [(ai < ma), (bj < mb)]
|
501
502
|
when [true, true]
|
502
503
|
if callbacks.respond_to?(:change)
|
503
|
-
event = Diff::LCS::ContextChange.new(
|
504
|
+
event = Diff::LCS::ContextChange.new("!", ai, ax, bj, bx)
|
504
505
|
event = yield event if block_given?
|
505
506
|
callbacks.change(event)
|
506
507
|
ai += 1
|
507
508
|
else
|
508
|
-
event = Diff::LCS::ContextChange.new(
|
509
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
509
510
|
event = yield event if block_given?
|
510
511
|
callbacks.discard_a(event)
|
511
512
|
ai += 1
|
512
513
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
513
|
-
event = Diff::LCS::ContextChange.new(
|
514
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
514
515
|
event = yield event if block_given?
|
515
516
|
callbacks.discard_b(event)
|
516
517
|
end
|
517
518
|
|
518
519
|
bj += 1
|
519
520
|
when [true, false]
|
520
|
-
event = Diff::LCS::ContextChange.new(
|
521
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
521
522
|
event = yield event if block_given?
|
522
523
|
callbacks.discard_a(event)
|
523
524
|
ai += 1
|
524
525
|
when [false, true]
|
525
|
-
event = Diff::LCS::ContextChange.new(
|
526
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
526
527
|
event = yield event if block_given?
|
527
528
|
callbacks.discard_b(event)
|
528
529
|
bj += 1
|
@@ -532,43 +533,43 @@ class << Diff::LCS
|
|
532
533
|
# Match
|
533
534
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
534
535
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
535
|
-
event = Diff::LCS::ContextChange.new(
|
536
|
+
event = Diff::LCS::ContextChange.new("=", ai, ax, bj, bx)
|
536
537
|
event = yield event if block_given?
|
537
538
|
callbacks.match(event)
|
538
539
|
ai += 1
|
539
540
|
bj += 1
|
540
541
|
end
|
541
542
|
|
542
|
-
while (ai < a_size)
|
543
|
+
while (ai < a_size) || (bj < b_size)
|
543
544
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
544
545
|
bx = string ? seq2[bj, 1] : seq2[bj]
|
545
546
|
|
546
547
|
case [(ai < a_size), (bj < b_size)]
|
547
548
|
when [true, true]
|
548
549
|
if callbacks.respond_to?(:change)
|
549
|
-
event = Diff::LCS::ContextChange.new(
|
550
|
+
event = Diff::LCS::ContextChange.new("!", ai, ax, bj, bx)
|
550
551
|
event = yield event if block_given?
|
551
552
|
callbacks.change(event)
|
552
553
|
ai += 1
|
553
554
|
else
|
554
|
-
event = Diff::LCS::ContextChange.new(
|
555
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
555
556
|
event = yield event if block_given?
|
556
557
|
callbacks.discard_a(event)
|
557
558
|
ai += 1
|
558
559
|
ax = string ? seq1[ai, 1] : seq1[ai]
|
559
|
-
event = Diff::LCS::ContextChange.new(
|
560
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
560
561
|
event = yield event if block_given?
|
561
562
|
callbacks.discard_b(event)
|
562
563
|
end
|
563
564
|
|
564
565
|
bj += 1
|
565
566
|
when [true, false]
|
566
|
-
event = Diff::LCS::ContextChange.new(
|
567
|
+
event = Diff::LCS::ContextChange.new("-", ai, ax, bj, bx)
|
567
568
|
event = yield event if block_given?
|
568
569
|
callbacks.discard_a(event)
|
569
570
|
ai += 1
|
570
571
|
when [false, true]
|
571
|
-
event = Diff::LCS::ContextChange.new(
|
572
|
+
event = Diff::LCS::ContextChange.new("+", ai, ax, bj, bx)
|
572
573
|
event = yield event if block_given?
|
573
574
|
callbacks.discard_b(event)
|
574
575
|
bj += 1
|
@@ -576,10 +577,12 @@ class << Diff::LCS
|
|
576
577
|
end
|
577
578
|
end
|
578
579
|
|
579
|
-
|
580
|
-
|
581
|
-
:
|
580
|
+
# standard:disable Style/HashSyntax
|
581
|
+
PATCH_MAP = { # :nodoc:
|
582
|
+
:patch => {"+" => "+", "-" => "-", "!" => "!", "=" => "="}.freeze,
|
583
|
+
:unpatch => {"+" => "-", "-" => "+", "!" => "!", "=" => "="}.freeze
|
582
584
|
}.freeze
|
585
|
+
# standard:enable Style/HashSyntax
|
583
586
|
|
584
587
|
# Applies a +patchset+ to the sequence +src+ according to the +direction+
|
585
588
|
# (<tt>:patch</tt> or <tt>:unpatch</tt>), producing a new sequence.
|
@@ -627,7 +630,7 @@ class << Diff::LCS
|
|
627
630
|
|
628
631
|
return src.respond_to?(:dup) ? src.dup : src unless has_changes
|
629
632
|
|
630
|
-
string = src.
|
633
|
+
string = src.is_a?(String)
|
631
634
|
# Start with a new empty type of the source's class
|
632
635
|
res = src.class.new
|
633
636
|
|
@@ -655,14 +658,14 @@ class << Diff::LCS
|
|
655
658
|
end
|
656
659
|
|
657
660
|
case action
|
658
|
-
when
|
661
|
+
when "-" # Remove details from the old string
|
659
662
|
while ai < op
|
660
663
|
res << (string ? src[ai, 1] : src[ai])
|
661
664
|
ai += 1
|
662
665
|
bj += 1
|
663
666
|
end
|
664
667
|
ai += 1
|
665
|
-
when
|
668
|
+
when "+"
|
666
669
|
while bj < np
|
667
670
|
res << (string ? src[ai, 1] : src[ai])
|
668
671
|
ai += 1
|
@@ -671,7 +674,7 @@ class << Diff::LCS
|
|
671
674
|
|
672
675
|
res << el
|
673
676
|
bj += 1
|
674
|
-
when
|
677
|
+
when "="
|
675
678
|
# This only appears in sdiff output with the SDiff callback.
|
676
679
|
# Therefore, we only need to worry about dealing with a single
|
677
680
|
# element.
|
@@ -679,7 +682,7 @@ class << Diff::LCS
|
|
679
682
|
|
680
683
|
ai += 1
|
681
684
|
bj += 1
|
682
|
-
when
|
685
|
+
when "!"
|
683
686
|
while ai < op
|
684
687
|
res << (string ? src[ai, 1] : src[ai])
|
685
688
|
ai += 1
|
@@ -693,14 +696,14 @@ class << Diff::LCS
|
|
693
696
|
end
|
694
697
|
when Diff::LCS::Change
|
695
698
|
case action
|
696
|
-
when
|
699
|
+
when "-"
|
697
700
|
while ai < change.position
|
698
701
|
res << (string ? src[ai, 1] : src[ai])
|
699
702
|
ai += 1
|
700
703
|
bj += 1
|
701
704
|
end
|
702
705
|
ai += 1
|
703
|
-
when
|
706
|
+
when "+"
|
704
707
|
while bj < change.position
|
705
708
|
res << (string ? src[ai, 1] : src[ai])
|
706
709
|
ai += 1
|
@@ -736,4 +739,4 @@ class << Diff::LCS
|
|
736
739
|
end
|
737
740
|
end
|
738
741
|
|
739
|
-
require
|
742
|
+
require "diff/lcs/backports"
|
data/lib/diff-lcs.rb
CHANGED
data/spec/change_spec.rb
CHANGED
@@ -1,89 +1,89 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
5
|
describe Diff::LCS::Change do
|
6
|
-
describe
|
7
|
-
subject { described_class.new(
|
8
|
-
it { should_not be_deleting
|
9
|
-
it { should
|
10
|
-
it { should_not be_unchanged
|
11
|
-
it { should_not be_changed
|
6
|
+
describe "an add" do
|
7
|
+
subject { described_class.new("+", 0, "element") }
|
8
|
+
it { should_not be_deleting }
|
9
|
+
it { should be_adding }
|
10
|
+
it { should_not be_unchanged }
|
11
|
+
it { should_not be_changed }
|
12
12
|
it { should_not be_finished_a }
|
13
13
|
it { should_not be_finished_b }
|
14
14
|
end
|
15
15
|
|
16
|
-
describe
|
17
|
-
subject { described_class.new(
|
18
|
-
it { should
|
19
|
-
it { should_not be_adding
|
20
|
-
it { should_not be_unchanged
|
21
|
-
it { should_not be_changed
|
16
|
+
describe "a delete" do
|
17
|
+
subject { described_class.new("-", 0, "element") }
|
18
|
+
it { should be_deleting }
|
19
|
+
it { should_not be_adding }
|
20
|
+
it { should_not be_unchanged }
|
21
|
+
it { should_not be_changed }
|
22
22
|
it { should_not be_finished_a }
|
23
23
|
it { should_not be_finished_b }
|
24
24
|
end
|
25
25
|
|
26
|
-
describe
|
27
|
-
subject { described_class.new(
|
28
|
-
it { should_not be_deleting
|
29
|
-
it { should_not be_adding
|
30
|
-
it { should
|
31
|
-
it { should_not be_changed
|
26
|
+
describe "an unchanged" do
|
27
|
+
subject { described_class.new("=", 0, "element") }
|
28
|
+
it { should_not be_deleting }
|
29
|
+
it { should_not be_adding }
|
30
|
+
it { should be_unchanged }
|
31
|
+
it { should_not be_changed }
|
32
32
|
it { should_not be_finished_a }
|
33
33
|
it { should_not be_finished_b }
|
34
34
|
end
|
35
35
|
|
36
|
-
describe
|
37
|
-
subject { described_class.new(
|
38
|
-
it { should_not be_deleting
|
39
|
-
it { should_not be_adding
|
40
|
-
it { should_not be_unchanged
|
41
|
-
it { should
|
36
|
+
describe "a changed" do
|
37
|
+
subject { described_class.new("!", 0, "element") }
|
38
|
+
it { should_not be_deleting }
|
39
|
+
it { should_not be_adding }
|
40
|
+
it { should_not be_unchanged }
|
41
|
+
it { should be_changed }
|
42
42
|
it { should_not be_finished_a }
|
43
43
|
it { should_not be_finished_b }
|
44
44
|
end
|
45
45
|
|
46
|
-
describe
|
47
|
-
subject { described_class.new(
|
48
|
-
it { should_not be_deleting
|
49
|
-
it { should_not be_adding
|
50
|
-
it { should_not be_unchanged
|
51
|
-
it { should_not be_changed
|
52
|
-
it { should
|
46
|
+
describe "a finished_a" do
|
47
|
+
subject { described_class.new(">", 0, "element") }
|
48
|
+
it { should_not be_deleting }
|
49
|
+
it { should_not be_adding }
|
50
|
+
it { should_not be_unchanged }
|
51
|
+
it { should_not be_changed }
|
52
|
+
it { should be_finished_a }
|
53
53
|
it { should_not be_finished_b }
|
54
54
|
end
|
55
55
|
|
56
|
-
describe
|
57
|
-
subject { described_class.new(
|
58
|
-
it { should_not be_deleting
|
59
|
-
it { should_not be_adding
|
60
|
-
it { should_not be_unchanged
|
61
|
-
it { should_not be_changed
|
56
|
+
describe "a finished_b" do
|
57
|
+
subject { described_class.new("<", 0, "element") }
|
58
|
+
it { should_not be_deleting }
|
59
|
+
it { should_not be_adding }
|
60
|
+
it { should_not be_unchanged }
|
61
|
+
it { should_not be_changed }
|
62
62
|
it { should_not be_finished_a }
|
63
|
-
it { should
|
63
|
+
it { should be_finished_b }
|
64
64
|
end
|
65
65
|
|
66
|
-
describe
|
67
|
-
it
|
68
|
-
action, position, element = described_class.new(
|
69
|
-
expect(action).to eq
|
66
|
+
describe "as array" do
|
67
|
+
it "should be converted" do
|
68
|
+
action, position, element = described_class.new("!", 0, "element")
|
69
|
+
expect(action).to eq "!"
|
70
70
|
expect(position).to eq 0
|
71
|
-
expect(element).to eq
|
71
|
+
expect(element).to eq "element"
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
describe Diff::LCS::ContextChange do
|
77
|
-
describe
|
78
|
-
it
|
77
|
+
describe "as array" do
|
78
|
+
it "should be converted" do
|
79
79
|
action, (old_position, old_element), (new_position, new_element) =
|
80
|
-
described_class.new(
|
80
|
+
described_class.new("!", 1, "old_element", 2, "new_element")
|
81
81
|
|
82
|
-
expect(action).to eq
|
82
|
+
expect(action).to eq "!"
|
83
83
|
expect(old_position).to eq 1
|
84
|
-
expect(old_element).to eq
|
84
|
+
expect(old_element).to eq "old_element"
|
85
85
|
expect(new_position).to eq 2
|
86
|
-
expect(new_element).to eq
|
86
|
+
expect(new_element).to eq "new_element"
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
data/spec/diff_spec.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "spec_helper"
|
4
4
|
|
5
|
-
describe Diff::LCS,
|
5
|
+
describe Diff::LCS, ".diff" do
|
6
6
|
include Diff::LCS::SpecHelper::Matchers
|
7
7
|
|
8
|
-
it
|
8
|
+
it "correctly diffs seq1 to seq2" do
|
9
9
|
diff_s1_s2 = Diff::LCS.diff(seq1, seq2)
|
10
10
|
expect(change_diff(correct_forward_diff)).to eq(diff_s1_s2)
|
11
11
|
end
|
12
12
|
|
13
|
-
it
|
13
|
+
it "correctly diffs seq2 to seq1" do
|
14
14
|
diff_s2_s1 = Diff::LCS.diff(seq2, seq1)
|
15
15
|
expect(change_diff(correct_backward_diff)).to eq(diff_s2_s1)
|
16
16
|
end
|
17
17
|
|
18
|
-
it
|
18
|
+
it "correctly diffs against an empty sequence" do
|
19
19
|
diff = Diff::LCS.diff(word_sequence, [])
|
20
20
|
correct_diff = [
|
21
21
|
[
|
22
|
-
[
|
23
|
-
[
|
24
|
-
[
|
25
|
-
[
|
22
|
+
["-", 0, "abcd"],
|
23
|
+
["-", 1, "efgh"],
|
24
|
+
["-", 2, "ijkl"],
|
25
|
+
["-", 3, "mnopqrstuvwxyz"]
|
26
26
|
]
|
27
27
|
]
|
28
28
|
|
@@ -30,22 +30,22 @@ describe Diff::LCS, '.diff' do
|
|
30
30
|
|
31
31
|
diff = Diff::LCS.diff([], word_sequence)
|
32
32
|
correct_diff.each do |hunk|
|
33
|
-
hunk.each
|
33
|
+
hunk.each { |change| change[0] = "+" }
|
34
34
|
end
|
35
35
|
expect(change_diff(correct_diff)).to eq(diff)
|
36
36
|
end
|
37
37
|
|
38
38
|
it "correctly diffs 'xx' and 'xaxb'" do
|
39
|
-
left =
|
40
|
-
right =
|
39
|
+
left = "xx"
|
40
|
+
right = "xaxb"
|
41
41
|
expect(Diff::LCS.patch(left, Diff::LCS.diff(left, right))).to eq(right)
|
42
42
|
end
|
43
43
|
|
44
|
-
it
|
44
|
+
it "returns an empty diff with (hello, hello)" do
|
45
45
|
expect(Diff::LCS.diff(hello, hello)).to be_empty
|
46
46
|
end
|
47
47
|
|
48
|
-
it
|
48
|
+
it "returns an empty diff with (hello_ary, hello_ary)" do
|
49
49
|
expect(Diff::LCS.diff(hello_ary, hello_ary)).to be_empty
|
50
50
|
end
|
51
51
|
end
|