diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 0b79c9e11..3bfa24ff3 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,17 +1,15 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2026-04-07 18:30:30 UTC using RuboCop version 1.85.1. +# on 2026-05-15 19:52:05 UTC using RuboCop version 1.85.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# TODO - [LH] -> Jan '25 (Updated deps and v10 prep) - 369 files inspected, 704 offenses detected, 112 offenses autocorrectable -# TODO - [LH] -> Mar '25 (v10 prep) - 370 files inspected, 721 offenses detected, 116 offenses autocorrectable # TODO - [LH] -> Dec '25 - 375 files inspected, 713 offenses detected, 109 offenses autocorrectable # TODO - [LH] -> Dec '25 (query prep) - 378 files inspected, 729 offenses detected, 109 offenses autocorrectable # TODO - [LH] -> Mar '26 (v11 prep) - 389 files inspected, 747 offenses detected, 108 offenses autocorrectable -# TODO - [LH] -> Apr '26 (v11 prep) - 393 files inspected, 740 offenses detected, 106 offenses autocorrectable +# TODO - [LH] -> May '26 (v11.0.0) - 391 files inspected, 740 offenses detected, 105 offenses autocorrectable # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). @@ -22,10 +20,17 @@ Layout/EmptyLineBetweenDefs: # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowInHeredoc. -Layout/TrailingWhitespace: +# Configuration parameters: EnforcedStyle. +# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines +Layout/EmptyLinesAroundModuleBody: + Exclude: + - 'lib/cucumber/glue/multiple_world.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Layout/HeredocIndentation: Exclude: - - 'spec/cucumber/step_match_search_spec.rb' + - 'lib/cucumber/glue/multiple_world.rb' # Offense count: 2 Lint/IneffectiveAccessModifier: @@ -214,12 +219,6 @@ RSpec/InstanceVariable: - 'spec/cucumber/step_match_spec.rb' - 'spec/support/shared_context/http_server.rb' -# Offense count: 2 -# This cop supports safe autocorrection (--autocorrect). -RSpec/LeadingSubject: - Exclude: - - 'spec/cucumber/rake/forked_cucumber_runner_spec.rb' - # Offense count: 2 # This cop supports safe autocorrection (--autocorrect). RSpec/MatchArray: diff --git a/CHANGELOG.md b/CHANGELOG.md index 66d0416ae..1b09725d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo ### Changed - Heavy refactor to the internals for message building (Used in formatters - should be no noticeable change) ([#1853](https://github.com/cucumber/cucumber-ruby/pull/1853) [luke-hill](https://github.com/luke-hill)) +- Refactor to internal error logic (No user facing changes) + +### Removed +- Removed a bunch of RSpec support logic that was no longer used in the codebase (This includes some legacy pending +logic and some old rspec helper files) +- Removed handling of a Ruby 2.1 system error (Minimum Ruby is now 3.2) ## [11.0.0] - 2026-04-14 ### Added diff --git a/lib/cucumber/errors.rb b/lib/cucumber/errors.rb index 9805539e8..97e3baa63 100644 --- a/lib/cucumber/errors.rb +++ b/lib/cucumber/errors.rb @@ -3,6 +3,49 @@ require 'cucumber/core/test/result' module Cucumber + # Raised when a step matches 2 or more StepDefinitions + class Ambiguous < StandardError + def initialize(step_name, step_definitions, used_guess) + # TODO: [LH] - Just use a heredoc here to fix this up + message = String.new + message << "Ambiguous match of \"#{step_name}\":\n\n" + message << step_definitions.map(&:backtrace_line).join("\n") + message << "\n\n" + message << "You can run again with --guess to make Cucumber be more smart about it\n" unless used_guess + super(message) + end + end + + class FeatureFolderNotFoundException < RuntimeError + def initialize(path) + @path = path + super + end + + def message + "No such file or directory - #{@path}" + end + end + + class FileNotFoundException < RuntimeError + attr_reader :path + + def initialize(original_exception, path) + @path = path + super(original_exception) + end + end + + # Raised when a StepDefinition's block invokes World#pending + class Pending < Core::Test::Result::Pending + end + + class TagExcess < StandardError + def initialize(messages) + super(messages.join("\n")) + end + end + # Raised when there is no matching StepDefinition for a step. class Undefined < Core::Test::Result::Undefined def self.from(result, step_name) @@ -27,27 +70,4 @@ def initialize(step_name) super %(Undefined dynamic step: "#{step_name}") end end - - # Raised when a StepDefinition's block invokes World#pending - class Pending < Core::Test::Result::Pending - end - - # Raised when a step matches 2 or more StepDefinitions - class Ambiguous < StandardError - def initialize(step_name, step_definitions, used_guess) - # TODO: [LH] - Just use a heredoc here to fix this up - message = String.new - message << "Ambiguous match of \"#{step_name}\":\n\n" - message << step_definitions.map(&:backtrace_line).join("\n") - message << "\n\n" - message << "You can run again with --guess to make Cucumber be more smart about it\n" unless used_guess - super(message) - end - end - - class TagExcess < StandardError - def initialize(messages) - super(messages.join("\n")) - end - end end diff --git a/lib/cucumber/glue/hook.rb b/lib/cucumber/glue/hook.rb index bdbe4114d..5f98bce5e 100644 --- a/lib/cucumber/glue/hook.rb +++ b/lib/cucumber/glue/hook.rb @@ -4,7 +4,6 @@ module Cucumber module Glue - # TODO: Kill pointless wrapper for Before, After and AfterStep hooks with fire class Hook attr_reader :id, :tag_expressions, :location, :name diff --git a/lib/cucumber/glue/multiple_world.rb b/lib/cucumber/glue/multiple_world.rb new file mode 100644 index 000000000..2a09da6ad --- /dev/null +++ b/lib/cucumber/glue/multiple_world.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Cucumber + module Glue + # Raised if there are 2 or more World blocks. + class MultipleWorld < StandardError + def initialize(first_proc, second_proc) + super(error_message(first_proc, second_proc)) + end + + def error_message(first_proc, second_proc) + <<~MESSAGE + You can only pass a proc to #World once, but it's happening + in 2 places: + #{Glue.backtrace_line(first_proc, 'World')} + #{Glue.backtrace_line(second_proc, 'World')} + Use Ruby modules instead to extend your worlds. See the Cucumber::Glue::Dsl#World RDoc + or http://wiki.github.com/cucumber/cucumber/a-whole-new-world. + + + MESSAGE + end + end + + end +end diff --git a/lib/cucumber/glue/nil_world.rb b/lib/cucumber/glue/nil_world.rb new file mode 100644 index 000000000..2512e482c --- /dev/null +++ b/lib/cucumber/glue/nil_world.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Cucumber + module Glue + # Raised if a World block returns Nil. + class NilWorld < StandardError + def initialize + super('World procs should never return nil') + end + end + end +end diff --git a/lib/cucumber/glue/registry_and_more.rb b/lib/cucumber/glue/registry_and_more.rb index f042c027a..0bd9120d9 100644 --- a/lib/cucumber/glue/registry_and_more.rb +++ b/lib/cucumber/glue/registry_and_more.rb @@ -15,6 +15,9 @@ require 'cucumber/step_match' require 'cucumber/events/step_definition_registered' +require_relative 'multiple_world' +require_relative 'nil_world' + module Cucumber module Glue def self.backtrace_line(proc, name) @@ -22,28 +25,6 @@ def self.backtrace_line(proc, name) "#{location}:in `#{name}'" end - # Raised if a World block returns Nil. - class NilWorld < StandardError - def initialize - super('World procs should never return nil') - end - end - - # Raised if there are 2 or more World blocks. - class MultipleWorld < StandardError - def initialize(first_proc, second_proc) - # TODO: [LH] - Just use a heredoc here to fix this up - message = String.new - message << "You can only pass a proc to #World once, but it's happening\n" - message << "in 2 places:\n\n" - message << Glue.backtrace_line(first_proc, 'World') << "\n" - message << Glue.backtrace_line(second_proc, 'World') << "\n\n" - message << "Use Ruby modules instead to extend your worlds. See the Cucumber::Glue::Dsl#World RDoc\n" - message << "or http://wiki.github.com/cucumber/cucumber/a-whole-new-world.\n\n" - super(message) - end - end - # TODO: This class has too many responsibilities, split off class RegistryAndMore attr_reader :current_world, :step_definitions diff --git a/lib/cucumber/rspec/doubles.rb b/lib/cucumber/rspec/doubles.rb index b7d872f9e..9ce7d01b4 100644 --- a/lib/cucumber/rspec/doubles.rb +++ b/lib/cucumber/rspec/doubles.rb @@ -5,15 +5,9 @@ World(RSpec::Mocks::ExampleMethods) Before do - if RSpec::Mocks::Version::STRING >= '2.9.9' - RSpec::Mocks.setup - else - RSpec::Mocks.setup(self) - end + RSpec::Mocks.setup(self) end After do - RSpec::Mocks.verify -ensure RSpec::Mocks.teardown end diff --git a/lib/cucumber/runtime.rb b/lib/cucumber/runtime.rb index 3315fd171..9a4328945 100644 --- a/lib/cucumber/runtime.rb +++ b/lib/cucumber/runtime.rb @@ -1,52 +1,27 @@ # frozen_string_literal: true require 'fileutils' -require 'cucumber/configuration' -require 'cucumber/load_path' -require 'cucumber/formatter/duration' -require 'cucumber/file_specs' -require 'cucumber/filters' -require 'cucumber/formatter/fanout' -require 'cucumber/gherkin/i18n' -require 'cucumber/glue/registry_wrapper' -require 'cucumber/step_match_search' -require 'cucumber/messages' -require 'cucumber/runtime/meta_message_builder' require 'sys/uname' -module Cucumber - module FixRuby21Bug9285 - def message - String(super).gsub('@ rb_sysopen ', '') - end - end - - class FileException < RuntimeError - attr_reader :path - - def initialize(original_exception, path) - @path = path - super(original_exception) - end - end - - class FileNotFoundException < FileException - end - - class FeatureFolderNotFoundException < RuntimeError - def initialize(path) - @path = path - super - end +require 'cucumber/core' +require 'cucumber/messages' - def message - "No such file or directory - #{@path}" - end - end +require_relative 'configuration' +require_relative 'errors' +require_relative 'file_specs' +require_relative 'filters' +require_relative 'load_path' +require_relative 'step_match_search' + +require_relative 'formatter/duration' +require_relative 'formatter/fanout' +require_relative 'gherkin/i18n' +require_relative 'glue/registry_wrapper' +require_relative 'runtime/meta_message_builder' +require_relative 'runtime/support_code' +require_relative 'runtime/user_interface' - require 'cucumber/core' - require 'cucumber/runtime/user_interface' - require 'cucumber/runtime/support_code' +module Cucumber class Runtime attr_reader :results, :support_code, :configuration diff --git a/spec/cucumber/glue/registry_and_more_spec.rb b/spec/cucumber/glue/registry_and_more_spec.rb index 11e9d2146..7083f6acb 100644 --- a/spec/cucumber/glue/registry_and_more_spec.rb +++ b/spec/cucumber/glue/registry_and_more_spec.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'spec_helper' require 'cucumber/glue/registry_and_more' require 'cucumber/cucumber_expressions/parameter_type' require 'support/fake_objects'