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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/Code-of-Conduct.md +74 -0
  4. data/Contributing.md +119 -0
  5. data/History.md +400 -0
  6. data/{License.rdoc → License.md} +6 -5
  7. data/Manifest.txt +36 -4
  8. data/README.rdoc +35 -23
  9. data/Rakefile +106 -11
  10. data/bin/htmldiff +7 -4
  11. data/bin/ldiff +4 -1
  12. data/docs/COPYING.txt +21 -22
  13. data/docs/artistic.txt +127 -0
  14. data/lib/diff/lcs/array.rb +1 -15
  15. data/lib/diff/lcs/backports.rb +9 -0
  16. data/lib/diff/lcs/block.rb +4 -18
  17. data/lib/diff/lcs/callbacks.rb +233 -230
  18. data/lib/diff/lcs/change.rb +114 -109
  19. data/lib/diff/lcs/htmldiff.rb +17 -18
  20. data/lib/diff/lcs/hunk.rb +232 -116
  21. data/lib/diff/lcs/internals.rb +308 -0
  22. data/lib/diff/lcs/ldiff.rb +138 -177
  23. data/lib/diff/lcs/string.rb +1 -15
  24. data/lib/diff/lcs.rb +597 -963
  25. data/lib/diff-lcs.rb +1 -3
  26. data/spec/change_spec.rb +89 -0
  27. data/spec/diff_spec.rb +32 -16
  28. data/spec/fixtures/aX +1 -0
  29. data/spec/fixtures/bXaX +1 -0
  30. data/spec/fixtures/ds1.csv +50 -0
  31. data/spec/fixtures/ds2.csv +51 -0
  32. data/spec/fixtures/ldiff/output.diff +4 -0
  33. data/spec/fixtures/ldiff/output.diff-c +7 -0
  34. data/spec/fixtures/ldiff/output.diff-e +3 -0
  35. data/spec/fixtures/ldiff/output.diff-f +3 -0
  36. data/spec/fixtures/ldiff/output.diff-u +5 -0
  37. data/spec/fixtures/ldiff/output.diff.chef +4 -0
  38. data/spec/fixtures/ldiff/output.diff.chef-c +15 -0
  39. data/spec/fixtures/ldiff/output.diff.chef-e +3 -0
  40. data/spec/fixtures/ldiff/output.diff.chef-f +3 -0
  41. data/spec/fixtures/ldiff/output.diff.chef-u +9 -0
  42. data/spec/fixtures/ldiff/output.diff.chef2 +7 -0
  43. data/spec/fixtures/ldiff/output.diff.chef2-c +20 -0
  44. data/spec/fixtures/ldiff/output.diff.chef2-d +7 -0
  45. data/spec/fixtures/ldiff/output.diff.chef2-e +7 -0
  46. data/spec/fixtures/ldiff/output.diff.chef2-f +7 -0
  47. data/spec/fixtures/ldiff/output.diff.chef2-u +16 -0
  48. data/spec/fixtures/new-chef +4 -0
  49. data/spec/fixtures/new-chef2 +17 -0
  50. data/spec/fixtures/old-chef +4 -0
  51. data/spec/fixtures/old-chef2 +14 -0
  52. data/spec/hunk_spec.rb +83 -0
  53. data/spec/issues_spec.rb +154 -0
  54. data/spec/lcs_spec.rb +36 -16
  55. data/spec/ldiff_spec.rb +87 -0
  56. data/spec/patch_spec.rb +198 -172
  57. data/spec/sdiff_spec.rb +99 -89
  58. data/spec/spec_helper.rb +149 -59
  59. data/spec/traverse_balanced_spec.rb +191 -167
  60. data/spec/traverse_sequences_spec.rb +105 -51
  61. metadata +218 -99
  62. data/.gemtest +0 -0
  63. data/History.rdoc +0 -54
  64. data/diff-lcs.gemspec +0 -51
  65. data/docs/artistic.html +0 -289
@@ -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
- # -*- ruby encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe "Diff::LCS.LCS and Diff::LCS.__lcs" do
5
+ describe Diff::LCS::Internals, '.lcs' do
6
6
  include Diff::LCS::SpecHelper::Matchers
7
7
 
8
- it "should return the correct raw values from Diff::LCS.__lcs" do
9
- res = Diff::LCS.__lcs(seq1, seq2)
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.should == correct_lcs.size
13
- res.should correctly_map_sequence(seq1).to_other_sequence(seq2)
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.should == correct_lcs
20
- x_seq2.should == correct_lcs
19
+ expect(x_seq1).to eq(correct_lcs)
20
+ expect(x_seq2).to eq(correct_lcs)
21
21
  end
22
22
 
23
- it "should return the correct compacted values from Diff::LCS.LCS" do
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.should == correct_lcs
26
- res.compact.should == res
39
+ expect(res).to eq(correct_lcs)
40
+ expect(res.compact).to eq(res)
27
41
  end
28
42
 
29
- it "should be transitive" do
43
+ it 'is transitive' do
30
44
  res = Diff::LCS.LCS(seq2, seq1)
31
- res.should == correct_lcs
32
- res.compact.should == res
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
- # vim: ft=ruby
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
@@ -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