diff --git a/.github/workflows/super_diff.yml b/.github/workflows/super_diff.yml index 0e144821..65850eee 100644 --- a/.github/workflows/super_diff.yml +++ b/.github/workflows/super_diff.yml @@ -61,6 +61,7 @@ jobs: rspec_appraisal: - rspec_lt_3_10 - rspec_gte_3_10 + - rspec_gte_3_13 env: BUNDLE_GEMFILE: gemfiles/${{ matrix.rails_appraisal }}_${{ matrix.rspec_appraisal }}.gemfile steps: diff --git a/.nvmrc b/.nvmrc index b009dfb9..87834047 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -lts/* +20.12.2 diff --git a/Appraisals b/Appraisals index ec91ea08..a50022e9 100644 --- a/Appraisals +++ b/Appraisals @@ -49,12 +49,26 @@ appraisals = { gem "rspec-mocks", "3.12.0" gem "rspec-support", "3.12.0" + gem "rspec-rails" if with_rails + end, + rspec_gte_3_13: + proc do |with_rails| + version = [">= 3.13", "< 4"] + + # gem "rspec", *version + + gem "rspec", "3.13.0" + gem "rspec-core", "3.13.0" + gem "rspec-expectations", "3.13.0" + gem "rspec-mocks", "3.13.0" + gem "rspec-support", "3.13.0" + gem "rspec-rails" if with_rails end } rails_appraisals = %i[no_rails rails_6_0 rails_6_1 rails_7_0] -rspec_appraisals = %i[rspec_lt_3_10 rspec_gte_3_10] +rspec_appraisals = %i[rspec_lt_3_10 rspec_gte_3_10 rspec_gte_3_13] rails_appraisals.each do |rails_appraisal| rspec_appraisals.each do |rspec_appraisal| diff --git a/gemfiles/no_rails_rspec_gte_3_13.gemfile b/gemfiles/no_rails_rspec_gte_3_13.gemfile new file mode 100644 index 00000000..a61d50b0 --- /dev/null +++ b/gemfiles/no_rails_rspec_gte_3_13.gemfile @@ -0,0 +1,23 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal" +gem "bundler-audit" +gem "childprocess" +gem "climate_control" +gem "pry-byebug", platform: :mri +gem "pry-nav", platform: :jruby +gem "rake" +gem "prettier_print" +gem "syntax_tree" +gem "syntax_tree-haml" +gem "syntax_tree-rbs" +gem "warnings_logger" +gem "rspec", "3.13.0" +gem "rspec-core", "3.13.0" +gem "rspec-expectations", "3.13.0" +gem "rspec-mocks", "3.13.0" +gem "rspec-support", "3.13.0" + +gemspec path: "../" diff --git a/gemfiles/rails_6_0_rspec_gte_3_13.gemfile b/gemfiles/rails_6_0_rspec_gte_3_13.gemfile new file mode 100644 index 00000000..ebff810d --- /dev/null +++ b/gemfiles/rails_6_0_rspec_gte_3_13.gemfile @@ -0,0 +1,30 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal" +gem "bundler-audit" +gem "childprocess" +gem "climate_control" +gem "pry-byebug", platform: :mri +gem "pry-nav", platform: :jruby +gem "rake" +gem "prettier_print" +gem "syntax_tree" +gem "syntax_tree-haml" +gem "syntax_tree-rbs" +gem "warnings_logger" +gem "activerecord-jdbcsqlite3-adapter", platform: :jruby +gem "jdbc-sqlite3", platform: :jruby +gem "net-ftp" +gem "combustion" +gem "rails", "~> 6.0.0" +gem "sqlite3", "~> 1.4.0", platform: [:ruby, :mswin, :mingw] +gem "rspec", "3.13.0" +gem "rspec-core", "3.13.0" +gem "rspec-expectations", "3.13.0" +gem "rspec-mocks", "3.13.0" +gem "rspec-support", "3.13.0" +gem "rspec-rails" + +gemspec path: "../" diff --git a/gemfiles/rails_6_1_rspec_gte_3_13.gemfile b/gemfiles/rails_6_1_rspec_gte_3_13.gemfile new file mode 100644 index 00000000..2d27faa1 --- /dev/null +++ b/gemfiles/rails_6_1_rspec_gte_3_13.gemfile @@ -0,0 +1,30 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal" +gem "bundler-audit" +gem "childprocess" +gem "climate_control" +gem "pry-byebug", platform: :mri +gem "pry-nav", platform: :jruby +gem "rake" +gem "prettier_print" +gem "syntax_tree" +gem "syntax_tree-haml" +gem "syntax_tree-rbs" +gem "warnings_logger" +gem "activerecord-jdbcsqlite3-adapter", platform: :jruby +gem "jdbc-sqlite3", platform: :jruby +gem "net-ftp" +gem "combustion" +gem "rails", "~> 6.1.0" +gem "sqlite3", "~> 1.4.0", platform: [:ruby, :mswin, :mingw] +gem "rspec", "3.13.0" +gem "rspec-core", "3.13.0" +gem "rspec-expectations", "3.13.0" +gem "rspec-mocks", "3.13.0" +gem "rspec-support", "3.13.0" +gem "rspec-rails" + +gemspec path: "../" diff --git a/gemfiles/rails_7_0_rspec_gte_3_13.gemfile b/gemfiles/rails_7_0_rspec_gte_3_13.gemfile new file mode 100644 index 00000000..0ca8c554 --- /dev/null +++ b/gemfiles/rails_7_0_rspec_gte_3_13.gemfile @@ -0,0 +1,30 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", git: "https://github.com/thoughtbot/appraisal" +gem "bundler-audit" +gem "childprocess" +gem "climate_control" +gem "pry-byebug", platform: :mri +gem "pry-nav", platform: :jruby +gem "rake" +gem "prettier_print" +gem "syntax_tree" +gem "syntax_tree-haml" +gem "syntax_tree-rbs" +gem "warnings_logger" +gem "activerecord-jdbcsqlite3-adapter", platform: :jruby +gem "jdbc-sqlite3", platform: :jruby +gem "net-ftp" +gem "combustion" +gem "rails", "~> 7.0.0" +gem "sqlite3", "~> 1.4.0", platform: [:ruby, :mswin, :mingw] +gem "rspec", "3.13.0" +gem "rspec-core", "3.13.0" +gem "rspec-expectations", "3.13.0" +gem "rspec-mocks", "3.13.0" +gem "rspec-support", "3.13.0" +gem "rspec-rails" + +gemspec path: "../" diff --git a/lib/super_diff/rspec.rb b/lib/super_diff/rspec.rb index 70bc5325..4a176005 100644 --- a/lib/super_diff/rspec.rb +++ b/lib/super_diff/rspec.rb @@ -79,7 +79,16 @@ def self.a_value_within_something?(value) end def self.aliased_matcher?(value) - value.is_a?(::RSpec::Matchers::AliasedMatcher) + if SuperDiff::RSpec.rspec_version < "3.13.0" + value.is_a?(::RSpec::Matchers::AliasedMatcher) + else # See Github issue #250. + !ordered_options?(value) && value.respond_to?(:base_matcher) + end + end + + def self.ordered_options?(value) + defined?(::ActiveSupport::OrderedOptions) && + value.is_a?(::ActiveSupport::OrderedOptions) end def self.rspec_version diff --git a/lib/super_diff/rspec/monkey_patches.rb b/lib/super_diff/rspec/monkey_patches.rb index b4bd6cfe..6e063ffe 100644 --- a/lib/super_diff/rspec/monkey_patches.rb +++ b/lib/super_diff/rspec/monkey_patches.rb @@ -309,73 +309,146 @@ def format(value) end module Matchers - class ExpectedsForMultipleDiffs - SuperDiff.insert_singleton_overrides(self) do - # Add a key for different sides - def from(expected) - return expected if self === expected - - text = colorizer.wrap("Diff:", SuperDiff.configuration.header_color) - - if SuperDiff.configuration.key_enabled? - text += - "\n\n" + - colorizer.wrap( - "┌ (Key) ──────────────────────────┐", - SuperDiff.configuration.border_color - ) + "\n" + - colorizer.wrap("│ ", SuperDiff.configuration.border_color) + - colorizer.wrap( - "‹-› in expected, not in actual", - SuperDiff.configuration.expected_color - ) + - colorizer.wrap(" │", SuperDiff.configuration.border_color) + - "\n" + - colorizer.wrap("│ ", SuperDiff.configuration.border_color) + - colorizer.wrap( - "‹+› in actual, not in expected", - SuperDiff.configuration.actual_color - ) + - colorizer.wrap(" │", SuperDiff.configuration.border_color) + - "\n" + - colorizer.wrap("│ ", SuperDiff.configuration.border_color) + - "‹ › in both expected and actual" + - colorizer.wrap(" │", SuperDiff.configuration.border_color) + - "\n" + - colorizer.wrap( - "└─────────────────────────────────┘", - SuperDiff.configuration.border_color - ) + if SuperDiff::RSpec.rspec_version < "3.13.0" + class ExpectedsForMultipleDiffs + SuperDiff.insert_singleton_overrides(self) do + # Add a key for different sides + def from(expected) + return expected if self === expected + + text = colorizer.wrap("Diff:", SuperDiff.configuration.header_color) + + if SuperDiff.configuration.key_enabled? + text += + "\n\n" + + colorizer.wrap( + "┌ (Key) ──────────────────────────┐", + SuperDiff.configuration.border_color + ) + "\n" + + colorizer.wrap("│ ", SuperDiff.configuration.border_color) + + colorizer.wrap( + "‹-› in expected, not in actual", + SuperDiff.configuration.expected_color + ) + + colorizer.wrap(" │", SuperDiff.configuration.border_color) + + "\n" + + colorizer.wrap("│ ", SuperDiff.configuration.border_color) + + colorizer.wrap( + "‹+› in actual, not in expected", + SuperDiff.configuration.actual_color + ) + + colorizer.wrap(" │", SuperDiff.configuration.border_color) + + "\n" + + colorizer.wrap("│ ", SuperDiff.configuration.border_color) + + "‹ › in both expected and actual" + + colorizer.wrap(" │", SuperDiff.configuration.border_color) + + "\n" + + colorizer.wrap( + "└─────────────────────────────────┘", + SuperDiff.configuration.border_color + ) + end + + new([[expected, text]]) end - new([[expected, text]]) + def colorizer + RSpec::Core::Formatters::ConsoleCodes + end end - def colorizer - RSpec::Core::Formatters::ConsoleCodes + SuperDiff.insert_overrides(self) do + # Add an extra line break + def message_with_diff(message, differ, actual) + diff = diffs(differ, actual) + + diff.empty? ? message : "#{message.rstrip}\n\n#{diff}" + end + + private + + # Add extra line breaks in between diffs, and colorize the word "Diff" + def diffs(differ, actual) + @expected_list + .map do |(expected, diff_label)| + diff = differ.diff(actual, expected) + next if diff.strip.empty? + diff_label + diff + end + .compact + .join("\n\n") + end end end + else + class MultiMatcherDiff + SuperDiff.insert_singleton_overrides(self) do + # Add a key for different sides + def from(expected, actual) + return expected if self === expected + + text = colorizer.wrap("Diff:", SuperDiff.configuration.header_color) + + if SuperDiff.configuration.key_enabled? + text += + "\n\n" + + colorizer.wrap( + "┌ (Key) ──────────────────────────┐", + SuperDiff.configuration.border_color + ) + "\n" + + colorizer.wrap("│ ", SuperDiff.configuration.border_color) + + colorizer.wrap( + "‹-› in expected, not in actual", + SuperDiff.configuration.expected_color + ) + + colorizer.wrap(" │", SuperDiff.configuration.border_color) + + "\n" + + colorizer.wrap("│ ", SuperDiff.configuration.border_color) + + colorizer.wrap( + "‹+› in actual, not in expected", + SuperDiff.configuration.actual_color + ) + + colorizer.wrap(" │", SuperDiff.configuration.border_color) + + "\n" + + colorizer.wrap("│ ", SuperDiff.configuration.border_color) + + "‹ › in both expected and actual" + + colorizer.wrap(" │", SuperDiff.configuration.border_color) + + "\n" + + colorizer.wrap( + "└─────────────────────────────────┘", + SuperDiff.configuration.border_color + ) + end - SuperDiff.insert_overrides(self) do - # Add an extra line break - def message_with_diff(message, differ, actual) - diff = diffs(differ, actual) + new([[expected, text, actual]]) + end - diff.empty? ? message : "#{message.rstrip}\n\n#{diff}" + def colorizer + RSpec::Core::Formatters::ConsoleCodes + end end - private + SuperDiff.insert_overrides(self) do + # Add an extra line break + def message_with_diff(message, differ) + diff = diffs(differ) + + diff.empty? ? message : "#{message.rstrip}\n\n#{diff}" + end - # Add extra line breaks in between diffs, and colorize the word "Diff" - def diffs(differ, actual) - @expected_list - .map do |(expected, diff_label)| - diff = differ.diff(actual, expected) - next if diff.strip.empty? - diff_label + diff - end - .compact - .join("\n\n") + private + + # Add extra line breaks in between diffs, and colorize the word "Diff" + def diffs(differ) + @expected_list + .map do |(expected, diff_label, actual)| + diff = differ.diff(actual, expected) + next if diff.strip.empty? + diff_label + diff + end + .compact + .join("\n\n") + end end end end