diff-lcs 1.1.3 → 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.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/Code-of-Conduct.md +74 -0
- data/Contributing.md +119 -0
- data/History.md +400 -0
- data/{License.rdoc → License.md} +6 -5
- data/Manifest.txt +36 -4
- data/README.rdoc +35 -23
- data/Rakefile +106 -11
- data/bin/htmldiff +7 -4
- data/bin/ldiff +4 -1
- data/docs/COPYING.txt +21 -22
- data/docs/artistic.txt +127 -0
- data/lib/diff/lcs/array.rb +1 -15
- data/lib/diff/lcs/backports.rb +9 -0
- data/lib/diff/lcs/block.rb +4 -18
- data/lib/diff/lcs/callbacks.rb +233 -230
- data/lib/diff/lcs/change.rb +114 -109
- data/lib/diff/lcs/htmldiff.rb +17 -18
- data/lib/diff/lcs/hunk.rb +232 -116
- data/lib/diff/lcs/internals.rb +308 -0
- data/lib/diff/lcs/ldiff.rb +138 -177
- data/lib/diff/lcs/string.rb +1 -15
- data/lib/diff/lcs.rb +597 -963
- data/lib/diff-lcs.rb +1 -3
- data/spec/change_spec.rb +89 -0
- data/spec/diff_spec.rb +32 -16
- data/spec/fixtures/aX +1 -0
- data/spec/fixtures/bXaX +1 -0
- data/spec/fixtures/ds1.csv +50 -0
- data/spec/fixtures/ds2.csv +51 -0
- data/spec/fixtures/ldiff/output.diff +4 -0
- data/spec/fixtures/ldiff/output.diff-c +7 -0
- data/spec/fixtures/ldiff/output.diff-e +3 -0
- data/spec/fixtures/ldiff/output.diff-f +3 -0
- data/spec/fixtures/ldiff/output.diff-u +5 -0
- data/spec/fixtures/ldiff/output.diff.chef +4 -0
- data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
- data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
- data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
- data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
- data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
- data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
- data/spec/fixtures/new-chef +4 -0
- data/spec/fixtures/new-chef2 +17 -0
- data/spec/fixtures/old-chef +4 -0
- data/spec/fixtures/old-chef2 +14 -0
- data/spec/hunk_spec.rb +83 -0
- data/spec/issues_spec.rb +154 -0
- data/spec/lcs_spec.rb +36 -16
- data/spec/ldiff_spec.rb +87 -0
- data/spec/patch_spec.rb +198 -172
- data/spec/sdiff_spec.rb +99 -89
- data/spec/spec_helper.rb +149 -59
- data/spec/traverse_balanced_spec.rb +191 -167
- data/spec/traverse_sequences_spec.rb +105 -51
- metadata +218 -99
- data/.gemtest +0 -0
- data/History.rdoc +0 -54
- data/diff-lcs.gemspec +0 -51
- data/docs/artistic.html +0 -289
data/spec/issues_spec.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'diff/lcs/hunk'
|
5
|
+
|
6
|
+
describe 'Diff::LCS Issues' do
|
7
|
+
include Diff::LCS::SpecHelper::Matchers
|
8
|
+
|
9
|
+
describe 'issue #1' do
|
10
|
+
shared_examples 'handles simple diffs' do |s1, s2, forward_diff|
|
11
|
+
before do
|
12
|
+
@diff_s1_s2 = Diff::LCS.diff(s1, s2)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'creates the correct diff' do
|
16
|
+
expect(change_diff(forward_diff)).to eq(@diff_s1_s2)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'creates the correct patch s1->s2' do
|
20
|
+
expect(Diff::LCS.patch(s1, @diff_s1_s2)).to eq(s2)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'creates the correct patch s2->s1' do
|
24
|
+
expect(Diff::LCS.patch(s2, @diff_s1_s2)).to eq(s1)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'string' do
|
29
|
+
it_has_behavior 'handles simple diffs', 'aX', 'bXaX', [
|
30
|
+
[
|
31
|
+
['+', 0, 'b'],
|
32
|
+
['+', 1, 'X']
|
33
|
+
]
|
34
|
+
]
|
35
|
+
it_has_behavior 'handles simple diffs', 'bXaX', 'aX', [
|
36
|
+
[
|
37
|
+
['-', 0, 'b'],
|
38
|
+
['-', 1, 'X']
|
39
|
+
]
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'array' do
|
44
|
+
it_has_behavior 'handles simple diffs', %w(a X), %w(b X a X), [
|
45
|
+
[
|
46
|
+
['+', 0, 'b'],
|
47
|
+
['+', 1, 'X']
|
48
|
+
]
|
49
|
+
]
|
50
|
+
it_has_behavior 'handles simple diffs', %w(b X a X), %w(a X), [
|
51
|
+
[
|
52
|
+
['-', 0, 'b'],
|
53
|
+
['-', 1, 'X']
|
54
|
+
]
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'issue #57' do
|
60
|
+
it 'should fail with a correct error' do
|
61
|
+
expect {
|
62
|
+
actual = { :category => 'app.rack.request' }
|
63
|
+
expected = { :category => 'rack.middleware', :title => 'Anonymous Middleware' }
|
64
|
+
expect(actual).to eq(expected)
|
65
|
+
}.to raise_error(RSpec::Expectations::ExpectationNotMetError)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'issue #60' do
|
70
|
+
it 'should produce unified output with correct context' do
|
71
|
+
old_data = <<-DATA_OLD.strip.split("\n").map(&:chomp)
|
72
|
+
{
|
73
|
+
"name": "x",
|
74
|
+
"description": "hi"
|
75
|
+
}
|
76
|
+
DATA_OLD
|
77
|
+
|
78
|
+
new_data = <<-DATA_NEW.strip.split("\n").map(&:chomp)
|
79
|
+
{
|
80
|
+
"name": "x",
|
81
|
+
"description": "lo"
|
82
|
+
}
|
83
|
+
DATA_NEW
|
84
|
+
|
85
|
+
diff = ::Diff::LCS.diff(old_data, new_data)
|
86
|
+
hunk = ::Diff::LCS::Hunk.new(old_data, new_data, diff.first, 3, 0)
|
87
|
+
|
88
|
+
expect(hunk.diff(:unified)).to eq(<<-EXPECTED.chomp)
|
89
|
+
@@ -1,5 +1,5 @@
|
90
|
+
{
|
91
|
+
"name": "x",
|
92
|
+
- "description": "hi"
|
93
|
+
+ "description": "lo"
|
94
|
+
}
|
95
|
+
EXPECTED
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'issue #65' do
|
100
|
+
def diff_lines(old_lines, new_lines)
|
101
|
+
file_length_difference = 0
|
102
|
+
previous_hunk = nil
|
103
|
+
output = []
|
104
|
+
|
105
|
+
Diff::LCS.diff(old_lines, new_lines).each do |piece|
|
106
|
+
hunk = Diff::LCS::Hunk.new(old_lines, new_lines, piece, 3, file_length_difference)
|
107
|
+
file_length_difference = hunk.file_length_difference
|
108
|
+
maybe_contiguous_hunks = (previous_hunk.nil? || hunk.merge(previous_hunk))
|
109
|
+
|
110
|
+
output << "#{previous_hunk.diff(:unified)}\n" unless maybe_contiguous_hunks
|
111
|
+
|
112
|
+
previous_hunk = hunk
|
113
|
+
end
|
114
|
+
output << "#{previous_hunk.diff(:unified, true)}\n" unless previous_hunk.nil?
|
115
|
+
output.join
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should not misplace the new chunk' do
|
119
|
+
old_data = [
|
120
|
+
'recipe[a::default]', 'recipe[b::default]', 'recipe[c::default]',
|
121
|
+
'recipe[d::default]', 'recipe[e::default]', 'recipe[f::default]',
|
122
|
+
'recipe[g::default]', 'recipe[h::default]', 'recipe[i::default]',
|
123
|
+
'recipe[j::default]', 'recipe[k::default]', 'recipe[l::default]',
|
124
|
+
'recipe[m::default]', 'recipe[n::default]'
|
125
|
+
]
|
126
|
+
|
127
|
+
new_data = [
|
128
|
+
'recipe[a::default]', 'recipe[c::default]', 'recipe[d::default]',
|
129
|
+
'recipe[e::default]', 'recipe[f::default]', 'recipe[g::default]',
|
130
|
+
'recipe[h::default]', 'recipe[i::default]', 'recipe[j::default]',
|
131
|
+
'recipe[k::default]', 'recipe[l::default]', 'recipe[m::default]',
|
132
|
+
'recipe[n::default]', 'recipe[o::new]', 'recipe[p::new]',
|
133
|
+
'recipe[q::new]', 'recipe[r::new]'
|
134
|
+
]
|
135
|
+
|
136
|
+
expect(diff_lines(old_data, new_data)).to eq(<<-EODIFF)
|
137
|
+
@@ -1,5 +1,4 @@
|
138
|
+
recipe[a::default]
|
139
|
+
-recipe[b::default]
|
140
|
+
recipe[c::default]
|
141
|
+
recipe[d::default]
|
142
|
+
recipe[e::default]
|
143
|
+
@@ -12,3 +11,7 @@
|
144
|
+
recipe[l::default]
|
145
|
+
recipe[m::default]
|
146
|
+
recipe[n::default]
|
147
|
+
+recipe[o::new]
|
148
|
+
+recipe[p::new]
|
149
|
+
+recipe[q::new]
|
150
|
+
+recipe[r::new]
|
151
|
+
EODIFF
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/spec/lcs_spec.rb
CHANGED
@@ -1,36 +1,56 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe
|
5
|
+
describe Diff::LCS::Internals, '.lcs' do
|
6
6
|
include Diff::LCS::SpecHelper::Matchers
|
7
7
|
|
8
|
-
it
|
9
|
-
res = Diff::LCS.
|
8
|
+
it 'returns a meaningful LCS array with (seq1, seq2)' do
|
9
|
+
res = Diff::LCS::Internals.lcs(seq1, seq2)
|
10
10
|
# The result of the LCS (less the +nil+ values) must be as long as the
|
11
11
|
# correct result.
|
12
|
-
res.compact.size.
|
13
|
-
res.
|
12
|
+
expect(res.compact.size).to eq(correct_lcs.size)
|
13
|
+
expect(res).to correctly_map_sequence(seq1).to_other_sequence(seq2)
|
14
14
|
|
15
15
|
# Compact these transformations and they should be the correct LCS.
|
16
16
|
x_seq1 = (0...res.size).map { |ix| res[ix] ? seq1[ix] : nil }.compact
|
17
17
|
x_seq2 = (0...res.size).map { |ix| res[ix] ? seq2[res[ix]] : nil }.compact
|
18
18
|
|
19
|
-
x_seq1.
|
20
|
-
x_seq2.
|
19
|
+
expect(x_seq1).to eq(correct_lcs)
|
20
|
+
expect(x_seq2).to eq(correct_lcs)
|
21
21
|
end
|
22
22
|
|
23
|
-
it
|
23
|
+
it 'returns all indexes with (hello, hello)' do
|
24
|
+
expect(Diff::LCS::Internals.lcs(hello, hello)).to \
|
25
|
+
eq((0...hello.size).to_a)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns all indexes with (hello_ary, hello_ary)' do
|
29
|
+
expect(Diff::LCS::Internals.lcs(hello_ary, hello_ary)).to \
|
30
|
+
eq((0...hello_ary.size).to_a)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe Diff::LCS, '.LCS' do
|
35
|
+
include Diff::LCS::SpecHelper::Matchers
|
36
|
+
|
37
|
+
it 'returns the correct compacted values from Diff::LCS.LCS' do
|
24
38
|
res = Diff::LCS.LCS(seq1, seq2)
|
25
|
-
res.
|
26
|
-
res.compact.
|
39
|
+
expect(res).to eq(correct_lcs)
|
40
|
+
expect(res.compact).to eq(res)
|
27
41
|
end
|
28
42
|
|
29
|
-
it
|
43
|
+
it 'is transitive' do
|
30
44
|
res = Diff::LCS.LCS(seq2, seq1)
|
31
|
-
res.
|
32
|
-
res.compact.
|
45
|
+
expect(res).to eq(correct_lcs)
|
46
|
+
expect(res.compact).to eq(res)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns %W(h e l l o) with (hello, hello)' do
|
50
|
+
expect(Diff::LCS.LCS(hello, hello)).to eq(hello.split(//))
|
33
51
|
end
|
34
|
-
end
|
35
52
|
|
36
|
-
|
53
|
+
it 'returns hello_ary with (hello_ary, hello_ary)' do
|
54
|
+
expect(Diff::LCS.LCS(hello_ary, hello_ary)).to eq(hello_ary)
|
55
|
+
end
|
56
|
+
end
|
data/spec/ldiff_spec.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'bin/ldiff' do
|
6
|
+
include CaptureSubprocessIO
|
7
|
+
|
8
|
+
fixtures = [
|
9
|
+
{ :name => 'output.diff', :left => 'aX', :right => 'bXaX' },
|
10
|
+
{ :name => 'output.diff.chef', :left => 'old-chef', :right => 'new-chef' },
|
11
|
+
{ :name => 'output.diff.chef2', :left => 'old-chef2', :right => 'new-chef2' }
|
12
|
+
].product([nil, '-e', '-f', '-c', '-u']).map { |(fixture, flag)|
|
13
|
+
fixture = fixture.dup
|
14
|
+
fixture[:flag] = flag
|
15
|
+
fixture
|
16
|
+
}
|
17
|
+
|
18
|
+
def self.test_ldiff(fixture)
|
19
|
+
desc = [
|
20
|
+
fixture[:flag],
|
21
|
+
"spec/fixtures/#{fixture[:left]}",
|
22
|
+
"spec/fixtures/#{fixture[:right]}",
|
23
|
+
'#',
|
24
|
+
'=>',
|
25
|
+
"spec/fixtures/ldiff/#{fixture[:name]}#{fixture[:flag]}"
|
26
|
+
].join(' ')
|
27
|
+
|
28
|
+
it desc do
|
29
|
+
expect(run_ldiff(fixture)).to eq(read_fixture(fixture))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
fixtures.each do |fixture|
|
34
|
+
test_ldiff(fixture)
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_fixture(options)
|
38
|
+
fixture = options.fetch(:name)
|
39
|
+
flag = options.fetch(:flag)
|
40
|
+
name = "spec/fixtures/ldiff/#{fixture}#{flag}"
|
41
|
+
data = IO.__send__(IO.respond_to?(:binread) ? :binread : :read, name)
|
42
|
+
clean_data(data, flag)
|
43
|
+
end
|
44
|
+
|
45
|
+
def clean_data(data, flag)
|
46
|
+
data =
|
47
|
+
case flag
|
48
|
+
when '-c', '-u'
|
49
|
+
clean_output_timestamp(data)
|
50
|
+
else
|
51
|
+
data
|
52
|
+
end
|
53
|
+
data.gsub(/\r\n?/, "\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
def clean_output_timestamp(data)
|
57
|
+
data.gsub(
|
58
|
+
%r{
|
59
|
+
^
|
60
|
+
[-+*]{3}
|
61
|
+
\s*
|
62
|
+
spec/fixtures/(\S+)
|
63
|
+
\s*
|
64
|
+
\d{4}-\d\d-\d\d
|
65
|
+
\s*
|
66
|
+
\d\d:\d\d:\d\d(?:\.\d+)
|
67
|
+
\s*
|
68
|
+
(?:[-+]\d{4}|Z)
|
69
|
+
}x,
|
70
|
+
'*** spec/fixtures/\1 0000-00-00 :00 =>:00 =>00.000000000 -0000'
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def run_ldiff(options)
|
75
|
+
flag = options.fetch(:flag)
|
76
|
+
left = options.fetch(:left)
|
77
|
+
right = options.fetch(:right)
|
78
|
+
|
79
|
+
stdout, stderr = capture_subprocess_io do
|
80
|
+
system("ruby -Ilib bin/ldiff #{flag} spec/fixtures/#{left} spec/fixtures/#{right}")
|
81
|
+
end
|
82
|
+
|
83
|
+
expect(stderr).to be_empty if RUBY_VERSION >= '1.9'
|
84
|
+
expect(stdout).not_to be_empty
|
85
|
+
clean_data(stdout, flag)
|
86
|
+
end
|
87
|
+
end
|