diff-lcs 1.6.2 → 2.0.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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -4
  3. data/CODE_OF_CONDUCT.md +152 -114
  4. data/CONTRIBUTING.md +91 -35
  5. data/CONTRIBUTORS.md +19 -9
  6. data/LICENCE.md +39 -11
  7. data/Manifest.txt +91 -83
  8. data/README.md +30 -17
  9. data/Rakefile +99 -73
  10. data/SECURITY.md +22 -27
  11. data/integration/compare/array_diff_spec.rb +10 -0
  12. data/integration/compare/hash_diff_spec.rb +25 -0
  13. data/integration/compare/string_diff_spec.rb +10 -0
  14. data/integration/rspec_differ_spec.rb +26 -0
  15. data/integration/rspec_expectations_spec.rb +32 -0
  16. data/integration/runner +20 -0
  17. data/lib/diff/lcs/block.rb +29 -24
  18. data/lib/diff/lcs/callbacks.rb +240 -242
  19. data/lib/diff/lcs/change.rb +102 -104
  20. data/lib/diff/lcs/hunk.rb +92 -155
  21. data/lib/diff/lcs/internals.rb +92 -96
  22. data/lib/diff/lcs/ldiff.rb +30 -38
  23. data/lib/diff/lcs/version.rb +1 -1
  24. data/lib/diff/lcs.rb +439 -466
  25. data/licenses/dco.txt +34 -0
  26. data/spec/hunk_spec.rb +32 -45
  27. data/spec/lcs_spec.rb +6 -6
  28. data/spec/ldiff_spec.rb +8 -8
  29. data/spec/spec_helper.rb +17 -27
  30. data/test/fixtures/ldiff/output.diff-c +7 -0
  31. data/test/fixtures/ldiff/output.diff-u +5 -0
  32. data/test/fixtures/ldiff/output.diff.bin2 +1 -0
  33. data/test/fixtures/ldiff/output.diff.bin2-c +1 -0
  34. data/test/fixtures/ldiff/output.diff.bin2-e +1 -0
  35. data/test/fixtures/ldiff/output.diff.bin2-f +1 -0
  36. data/test/fixtures/ldiff/output.diff.bin2-u +1 -0
  37. data/{spec → test}/fixtures/ldiff/output.diff.chef-c +2 -2
  38. data/test/fixtures/ldiff/output.diff.chef-u +9 -0
  39. data/{spec → test}/fixtures/ldiff/output.diff.chef2-c +2 -2
  40. data/{spec → test}/fixtures/ldiff/output.diff.chef2-u +2 -2
  41. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-c +9 -0
  42. data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-u +7 -0
  43. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-c +9 -0
  44. data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-u +7 -0
  45. data/test/fixtures/ldiff/output.diff.issue95_trailing_context-c +9 -0
  46. data/test/fixtures/ldiff/output.diff.issue95_trailing_context-u +6 -0
  47. data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1-c +2 -2
  48. data/test/fixtures/ldiff/output.diff.missing_new_line1-u +9 -0
  49. data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2-c +2 -2
  50. data/test/fixtures/ldiff/output.diff.missing_new_line2-u +9 -0
  51. data/test/test_block.rb +34 -0
  52. data/test/test_change.rb +234 -0
  53. data/test/test_diff.rb +53 -0
  54. data/test/test_helper.rb +225 -0
  55. data/test/test_hunk.rb +72 -0
  56. data/test/test_issues.rb +168 -0
  57. data/test/test_lcs.rb +47 -0
  58. data/test/test_ldiff.rb +89 -0
  59. data/test/test_patch.rb +362 -0
  60. data/test/test_sdiff.rb +167 -0
  61. data/test/test_traverse_balanced.rb +322 -0
  62. data/test/test_traverse_sequences.rb +187 -0
  63. metadata +205 -119
  64. data/.rspec +0 -1
  65. data/bin/htmldiff +0 -35
  66. data/lib/diff/lcs/backports.rb +0 -13
  67. data/lib/diff/lcs/htmldiff.rb +0 -160
  68. data/mise.toml +0 -5
  69. data/spec/fixtures/ldiff/output.diff-c +0 -7
  70. data/spec/fixtures/ldiff/output.diff-e +0 -3
  71. data/spec/fixtures/ldiff/output.diff-f +0 -3
  72. data/spec/fixtures/ldiff/output.diff-u +0 -5
  73. data/spec/fixtures/ldiff/output.diff.bin2 +0 -1
  74. data/spec/fixtures/ldiff/output.diff.bin2-c +0 -1
  75. data/spec/fixtures/ldiff/output.diff.bin2-e +0 -1
  76. data/spec/fixtures/ldiff/output.diff.bin2-f +0 -1
  77. data/spec/fixtures/ldiff/output.diff.bin2-u +0 -1
  78. data/spec/fixtures/ldiff/output.diff.chef-e +0 -3
  79. data/spec/fixtures/ldiff/output.diff.chef-f +0 -3
  80. data/spec/fixtures/ldiff/output.diff.chef-u +0 -9
  81. data/spec/fixtures/ldiff/output.diff.chef2-e +0 -7
  82. data/spec/fixtures/ldiff/output.diff.chef2-f +0 -7
  83. data/spec/fixtures/ldiff/output.diff.empty.vs.four_lines-c +0 -9
  84. data/spec/fixtures/ldiff/output.diff.empty.vs.four_lines-u +0 -7
  85. data/spec/fixtures/ldiff/output.diff.four_lines.vs.empty-c +0 -9
  86. data/spec/fixtures/ldiff/output.diff.four_lines.vs.empty-u +0 -7
  87. data/spec/fixtures/ldiff/output.diff.issue95_trailing_context-c +0 -9
  88. data/spec/fixtures/ldiff/output.diff.issue95_trailing_context-u +0 -6
  89. data/spec/fixtures/ldiff/output.diff.missing_new_line1-u +0 -9
  90. data/spec/fixtures/ldiff/output.diff.missing_new_line2-u +0 -9
  91. /data/{docs → licenses}/COPYING.txt +0 -0
  92. /data/{docs → licenses}/artistic.txt +0 -0
  93. /data/{spec → test}/fixtures/123_x +0 -0
  94. /data/{spec → test}/fixtures/456_x +0 -0
  95. /data/{spec → test}/fixtures/aX +0 -0
  96. /data/{spec → test}/fixtures/bXaX +0 -0
  97. /data/{spec → test}/fixtures/ds1.csv +0 -0
  98. /data/{spec → test}/fixtures/ds2.csv +0 -0
  99. /data/{spec → test}/fixtures/empty +0 -0
  100. /data/{spec → test}/fixtures/file1.bin +0 -0
  101. /data/{spec → test}/fixtures/file2.bin +0 -0
  102. /data/{spec → test}/fixtures/four_lines +0 -0
  103. /data/{spec → test}/fixtures/four_lines_with_missing_new_line +0 -0
  104. /data/{spec → test}/fixtures/ldiff/diff.missing_new_line1-e +0 -0
  105. /data/{spec → test}/fixtures/ldiff/diff.missing_new_line1-f +0 -0
  106. /data/{spec → test}/fixtures/ldiff/diff.missing_new_line2-e +0 -0
  107. /data/{spec → test}/fixtures/ldiff/diff.missing_new_line2-f +0 -0
  108. /data/{spec → test}/fixtures/ldiff/error.diff.chef-e +0 -0
  109. /data/{spec → test}/fixtures/ldiff/error.diff.chef-f +0 -0
  110. /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line1-e +0 -0
  111. /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line1-f +0 -0
  112. /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line2-e +0 -0
  113. /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line2-f +0 -0
  114. /data/{spec → test}/fixtures/ldiff/output.diff +0 -0
  115. /data/{spec → test}/fixtures/ldiff/output.diff.bin1 +0 -0
  116. /data/{spec → test}/fixtures/ldiff/output.diff.bin1-c +0 -0
  117. /data/{spec → test}/fixtures/ldiff/output.diff.bin1-e +0 -0
  118. /data/{spec → test}/fixtures/ldiff/output.diff.bin1-f +0 -0
  119. /data/{spec → test}/fixtures/ldiff/output.diff.bin1-u +0 -0
  120. /data/{spec → test}/fixtures/ldiff/output.diff.chef +0 -0
  121. /data/{spec → test}/fixtures/ldiff/output.diff.chef2 +0 -0
  122. /data/{spec → test}/fixtures/ldiff/output.diff.chef2-d +0 -0
  123. /data/{spec → test}/fixtures/ldiff/output.diff.empty.vs.four_lines +0 -0
  124. /data/{spec → test}/fixtures/ldiff/output.diff.empty.vs.four_lines-e +0 -0
  125. /data/{spec → test}/fixtures/ldiff/output.diff.empty.vs.four_lines-f +0 -0
  126. /data/{spec → test}/fixtures/ldiff/output.diff.four_lines.vs.empty +0 -0
  127. /data/{spec → test}/fixtures/ldiff/output.diff.four_lines.vs.empty-e +0 -0
  128. /data/{spec → test}/fixtures/ldiff/output.diff.four_lines.vs.empty-f +0 -0
  129. /data/{spec → test}/fixtures/ldiff/output.diff.issue95_trailing_context +0 -0
  130. /data/{spec → test}/fixtures/ldiff/output.diff.issue95_trailing_context-e +0 -0
  131. /data/{spec → test}/fixtures/ldiff/output.diff.issue95_trailing_context-f +0 -0
  132. /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1 +0 -0
  133. /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1-e +0 -0
  134. /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1-f +0 -0
  135. /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2 +0 -0
  136. /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2-e +0 -0
  137. /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2-f +0 -0
  138. /data/{spec → test}/fixtures/new-chef +0 -0
  139. /data/{spec → test}/fixtures/new-chef2 +0 -0
  140. /data/{spec → test}/fixtures/old-chef +0 -0
  141. /data/{spec → test}/fixtures/old-chef2 +0 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Integration test to verify diff-lcs 2.0 works with RSpec's differ
4
+ # This runs RSpec with diff-lcs 1.x installed but loads the repo version
5
+
6
+ RSpec.describe "Diff::LCS 2.0 with RSpec::Support::Differ" do
7
+ let(:differ) { RSpec::Support::Differ.new }
8
+
9
+ it "produces diff output for multiline strings" do
10
+ expected = "foo\nzap\nbar\n"
11
+ actual = "foo\nbar\nzap\n"
12
+
13
+ diff = differ.diff(actual, expected)
14
+
15
+ expect(diff).to be_a(String)
16
+ expect(diff).not_to be_empty
17
+ end
18
+
19
+ it "handles identical strings" do
20
+ str = "same\n"
21
+ diff = differ.diff(str, str)
22
+
23
+ # May return empty or just newline depending on implementation
24
+ expect(diff.strip).to be_empty
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Integration test for RSpec expectation failures that use diff-lcs
4
+ # Verifies that diff output is generated correctly with diff-lcs 2.0
5
+
6
+ RSpec.describe "Diff::LCS 2.0 with RSpec expectations" do
7
+ it "produces diff for failed multiline string equality" do
8
+ expect {
9
+ expect("foo\nbar\nbaz").to eq("foo\nqux\nbaz")
10
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError) do |error|
11
+ expect(error.message).to include("Diff:")
12
+ expect(error.message).to match(/[-+](qux|bar)/)
13
+ end
14
+ end
15
+
16
+ it "produces diff for failed hash equality" do
17
+ expect {
18
+ expect({a: 1, b: 2}).to eq({a: 1, b: 3})
19
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError) do |error|
20
+ expect(error.message).to include("Diff:")
21
+ end
22
+ end
23
+
24
+ it "does not crash when comparing complex objects" do
25
+ obj1 = {a: [1, 2, 3], b: "test"}
26
+ obj2 = {a: [1, 4, 3], b: "test"}
27
+
28
+ expect {
29
+ expect(obj1).to eq(obj2)
30
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rbconfig"
4
+ require "rubygems"
5
+
6
+ if ENV["CI"]
7
+ vendor_dir = Dir.glob(File.join(Dir.pwd, "vendor", "bundle", "{ruby,jruby,truffleruby}", "*")).max
8
+ unless vendor_dir && Dir.exist?(vendor_dir)
9
+ fail "vendor bundle not found; expected vendor/bundle/ruby/*"
10
+ end
11
+
12
+ # Prefer vendored gems, fall back to system gem dir
13
+ ENV["GEM_HOME"] = vendor_dir
14
+ ENV["GEM_PATH"] = "#{vendor_dir}:#{Gem.default_dir}"
15
+
16
+ # Ensure Gem.path is updated for the running process (affects Gem.lookup)
17
+ Gem.use_paths(ENV["GEM_HOME"], ENV["GEM_PATH"].split(":"))
18
+ end
19
+
20
+ exec RbConfig.ruby, "-S", *ARGV
@@ -1,37 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # A block is an operation removing, adding, or changing a group of items.
4
- # Basically, this is just a list of changes, where each change adds or
5
- # deletes a single item. Used by bin/ldiff.
6
- class Diff::LCS::Block
7
- attr_reader :changes, :insert, :remove
3
+ Diff::LCS::Block = Data.define(:changes, :insert, :remove) # :nodoc:
8
4
 
9
- def initialize(chunk)
10
- @changes = []
11
- @insert = []
12
- @remove = []
5
+ # A block is an operation removing, adding, or changing a group of items, a list of
6
+ # changes, where each change adds or deletes a single item.
7
+ #
8
+ # Used by bin/ldiff.
9
+ class Diff::LCS::Block
10
+ def self.from_chunk(chunk)
11
+ changes, insert, remove = [], [], []
13
12
 
14
- chunk.each do |item|
15
- @changes << item
16
- @remove << item if item.deleting?
17
- @insert << item if item.adding?
13
+ chunk.each do
14
+ changes << _1
15
+ remove << _1 if _1.deleting?
16
+ insert << _1 if _1.adding?
18
17
  end
18
+
19
+ new(changes: changes.freeze, remove: remove.freeze, insert: insert.freeze)
19
20
  end
20
21
 
21
- def diff_size
22
- @insert.size - @remove.size
22
+ class << self
23
+ private :new, :[]
23
24
  end
24
25
 
26
+ private :with
27
+
28
+ def diff_size = insert.size - remove.size
29
+
25
30
  def op
26
- case [@remove.empty?, @insert.empty?]
27
- when [false, false]
28
- "!"
29
- when [false, true]
30
- "-"
31
- when [true, false]
32
- "+"
33
- else # [true, true]
34
- "^"
31
+ case [remove, insert]
32
+ # Unchanged
33
+ in [[], []] then "^"
34
+ # Delete
35
+ in [_, []] then "-"
36
+ # Insert
37
+ in [[], _] then "+"
38
+ # Conflict
39
+ in [_, _] then "!"
35
40
  end
36
41
  end
37
42
  end