diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 35af4cd1..145f46bb 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,17 +1,15 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
-# on 2026-01-06 12:52:49 UTC using RuboCop version 1.81.7.
+# on 2026-04-06 21:27:57 UTC using RuboCop version 1.81.7.
# 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] v14 Pre-release iteration -> 58 files inspected, 392 offenses detected, 100 offenses auto-correctable
-# TODO: [LH] v14 Pre-release iteration 2 (Rubocop upgrade) -> 60 files inspected, 324 offenses detected, 86 offenses autocorrectable
-# TODO: [LH] v14 Pre-release iteration 3 (Rubocop additional upgrade) -> 60 files inspected, 267 offenses detected, 26 offenses autocorrectable
# TODO: [LH] v15 Release incoming (Minimum ruby bump) -> 60 files inspected, 234 offenses detected, 12 offenses autocorrectable
# TODO: [LH] v15.1 (Minor fixes) -> 60 files inspected, 239 offenses detected, 15 offenses autocorrectable
# TODO: [LH] v16 (Gherkin/Message bump) -> 61 files inspected, 272 offenses detected, 60 offenses autocorrectable
+# TODO: [LH] v16.2 (Generic refactors / new events) -> 79 files inspected, 222 offenses detected, 10 offenses autocorrectable
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
diff --git a/lib/cucumber/core/compiler.rb b/lib/cucumber/core/compiler.rb
index 7cfecf02..252eb26c 100644
--- a/lib/cucumber/core/compiler.rb
+++ b/lib/cucumber/core/compiler.rb
@@ -16,7 +16,7 @@ class Compiler
attr_reader :receiver, :gherkin_query, :id_generator
private :receiver, :gherkin_query, :id_generator
- def initialize(receiver, gherkin_query, event_bus = nil)
+ def initialize(receiver, gherkin_query, event_bus)
@receiver = receiver
@id_generator = Cucumber::Messages::Helpers::IdGenerator::UUID.new
@gherkin_query = gherkin_query
@@ -42,7 +42,7 @@ def create_test_case(pickle)
parent_locations = parent_locations_from_pickle(pickle)
tags = tags_from_pickle(pickle, uri)
Test::Case.new(id_generator.new_id, pickle.name, test_steps, location, parent_locations, tags, pickle.language).tap do |test_case|
- @event_bus&.test_case_created(test_case, pickle)
+ @event_bus.test_case_created(test_case, pickle)
end
end
@@ -50,7 +50,7 @@ def create_test_step(pickle_step, uri)
location = location_from_pickle_step(pickle_step, uri)
multiline_arg = create_multiline_arg(pickle_step, uri)
Test::Step.new(id_generator.new_id, pickle_step.text, location, multiline_arg).tap do |test_step|
- @event_bus&.test_step_created(test_step, pickle_step)
+ @event_bus.test_step_created(test_step, pickle_step)
end
end
diff --git a/lib/cucumber/core/gherkin/document.rb b/lib/cucumber/core/gherkin/document.rb
index c8dd1fa2..9b6f3b44 100644
--- a/lib/cucumber/core/gherkin/document.rb
+++ b/lib/cucumber/core/gherkin/document.rb
@@ -6,10 +6,10 @@ module Gherkin
class Document
attr_reader :uri, :body, :language
- def initialize(uri, body, language = nil)
- @uri = uri
- @body = body
- @language = language || 'en'
+ def initialize(uri, body, language = 'en')
+ @uri = uri
+ @body = body
+ @language = language
end
def to_s
diff --git a/lib/cucumber/core/gherkin/parser.rb b/lib/cucumber/core/gherkin/parser.rb
index 2029c0d9..3ee8eea6 100644
--- a/lib/cucumber/core/gherkin/parser.rb
+++ b/lib/cucumber/core/gherkin/parser.rb
@@ -64,15 +64,11 @@ def update_gherkin_query(message)
end
def type(message)
- if !message.gherkin_document.nil?
- :gherkin_document
- elsif !message.pickle.nil?
- :pickle
- elsif message.parse_error
- :parse_error
- else
- :unknown
- end
+ return :gherkin_document if message.gherkin_document
+ return :pickle if message.pickle
+ return :parse_error if message.parse_error
+
+ :unknown
end
end
end
diff --git a/lib/cucumber/core/platform.rb b/lib/cucumber/core/platform.rb
deleted file mode 100644
index 341fa07e..00000000
--- a/lib/cucumber/core/platform.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-# Detect the platform we're running on so we can tweak behaviour
-# in various places.
-require 'rbconfig'
-
-module Cucumber
- unless defined?(Cucumber::VERSION)
- JRUBY = defined?(JRUBY_VERSION)
- IRONRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ironruby'
- WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
- OS_X = RbConfig::CONFIG['host_os'] =~ /darwin/
- WINDOWS_MRI = WINDOWS && !JRUBY && !IRONRUBY
- RUBY_2_0 = RUBY_VERSION =~ /^2\.0/
- RUBY_1_9 = RUBY_VERSION =~ /^1\.9/
- end
-end
diff --git a/lib/cucumber/core/test/action.rb b/lib/cucumber/core/test/action.rb
index 2f49ccf5..79e81000 100644
--- a/lib/cucumber/core/test/action.rb
+++ b/lib/cucumber/core/test/action.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
-require 'cucumber/core/test/location'
-require 'cucumber/core/test/result'
-require 'cucumber/core/test/timer'
+require_relative 'location'
+require_relative 'result'
+require_relative 'timer'
-require 'cucumber/core/test/action/defined'
-require 'cucumber/core/test/action/undefined'
-require 'cucumber/core/test/action/unskippable'
+require_relative 'action/defined'
+require_relative 'action/undefined'
+require_relative 'action/unskippable'
diff --git a/lib/cucumber/core/test/around_hook.rb b/lib/cucumber/core/test/around_hook.rb
index cf0d3108..d0558a9e 100644
--- a/lib/cucumber/core/test/around_hook.rb
+++ b/lib/cucumber/core/test/around_hook.rb
@@ -13,10 +13,6 @@ def describe_to(visitor, *, &)
visitor.around_hook(self, *, &)
end
- def hook?
- true
- end
-
def execute(*_args, &continue)
@timer.start
@block.call(continue)
@@ -27,6 +23,10 @@ def execute(*_args, &continue)
failed(e)
end
+ def hook?
+ true
+ end
+
private
def failed(exception)
diff --git a/lib/cucumber/core/test/case.rb b/lib/cucumber/core/test/case.rb
index 608431e2..f3a585da 100644
--- a/lib/cucumber/core/test/case.rb
+++ b/lib/cucumber/core/test/case.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
-require 'cucumber/core/test/result'
require 'cucumber/tag_expressions'
+require_relative 'result'
+
module Cucumber
module Core
module Test
@@ -22,8 +23,8 @@ def initialize(id, name, test_steps, location, parent_locations, tags, language,
@around_hooks = around_hooks
end
- def step_count
- test_steps.count
+ def ==(other)
+ eql?(other)
end
def describe_to(visitor, *args)
@@ -37,20 +38,25 @@ def describe_to(visitor, *args)
self
end
- def with_steps(test_steps)
- self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
+ def eql?(other)
+ other.hash == hash
end
- def with_around_hooks(around_hooks)
- self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
+ def hash
+ location.hash
end
- def match_tags?(*expressions)
- expressions.flatten.all? { |expression| match_single_tag_expression?(expression) }
+ def inspect
+ "#<#{self.class}: #{location}>"
end
- def match_name?(name_regexp)
- name =~ name_regexp
+ def matching_locations
+ [
+ parent_locations,
+ location,
+ tags.map(&:location),
+ test_steps.map(&:matching_locations)
+ ].flatten
end
def match_locations?(queried_locations)
@@ -61,29 +67,24 @@ def match_locations?(queried_locations)
end
end
- def matching_locations
- [
- parent_locations,
- location,
- tags.map(&:location),
- test_steps.map(&:matching_locations)
- ].flatten
+ def match_name?(name_regexp)
+ name =~ name_regexp
end
- def inspect
- "#<#{self.class}: #{location}>"
+ def match_tags?(*expressions)
+ expressions.flatten.all? { |expression| match_single_tag_expression?(expression) }
end
- def hash
- location.hash
+ def step_count
+ test_steps.count
end
- def eql?(other)
- other.hash == hash
+ def with_around_hooks(around_hooks)
+ self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
end
- def ==(other)
- eql?(other)
+ def with_steps(test_steps)
+ self.class.new(id, name, test_steps, location, parent_locations, tags, language, around_hooks)
end
private
diff --git a/lib/cucumber/core/test/data_table.rb b/lib/cucumber/core/test/data_table.rb
index f8d88411..bc03f28b 100644
--- a/lib/cucumber/core/test/data_table.rb
+++ b/lib/cucumber/core/test/data_table.rb
@@ -16,60 +16,52 @@ module Test
#
# And a matching StepDefinition:
#
- # Given /I have:/ do |table|
+ # Given('I have:') do |table|
# data = table.raw
# end
#
# This will store [['a', 'b'], ['c', 'd']] in the data variable.
#
class DataTable
- # Creates a new instance. +raw+ should be an Array of Array of String
- # or an Array of Hash
+ attr_reader :raw
+
+ # Creates a new instance. +raw+ should be a square (2d), array of strings or an array of hashes
+ #
# You don't typically create your own DataTable objects - Cucumber will do
# it internally and pass them to your Step Definitions.
- #
def initialize(rows)
raw = ensure_array_of_array(rows)
verify_rows_are_same_length(raw)
@raw = raw.freeze
end
- attr_reader :raw
-
- def describe_to(visitor, *)
- visitor.data_table(self, *)
- end
- def to_step_definition_arg
- dup
+ def ==(other)
+ other.class == self.class && raw == other.raw
end
def data_table?
true
end
+ def describe_to(visitor, *)
+ visitor.data_table(self, *)
+ end
+
def doc_string?
false
end
# Creates a copy of this table
- #
def dup
self.class.new(raw.dup)
end
- # Returns a new, transposed table. Example:
- #
- # | a | 7 | 4 |
- # | b | 9 | 2 |
- #
- # Gets converted into the following:
- #
- # | a | b |
- # | 7 | 9 |
- # | 4 | 2 |
- #
- def transpose
- self.class.new(raw.transpose)
+ def inspect
+ %{#<#{self.class} #{raw.inspect}>}
+ end
+
+ def lines_count
+ raw.count
end
def map(&block)
@@ -80,26 +72,26 @@ def map(&block)
self.class.new(new_raw)
end
- def lines_count
- raw.count
- end
-
- def ==(other)
- other.class == self.class && raw == other.raw
+ def to_step_definition_arg
+ dup
end
- def inspect
- %{#<#{self.class} #{raw.inspect})>}
+ # Returns a new, transposed table. Example:
+ #
+ # | a | 7 | 4 |
+ # | b | 9 | 2 |
+ #
+ # Gets converted into the following:
+ #
+ # | a | b |
+ # | 7 | 9 |
+ # | 4 | 2 |
+ def transpose
+ self.class.new(raw.transpose)
end
private
- def verify_rows_are_same_length(raw)
- raw.transpose
- rescue IndexError
- raise ArgumentError, 'Rows must all be the same length'
- end
-
def ensure_array_of_array(array)
array[0].is_a?(Hash) ? hashes_to_array(array) : array
end
@@ -108,6 +100,12 @@ def hashes_to_array(hashes)
header = hashes[0].keys.sort
[header] + hashes.map { |hash| header.map { |key| hash[key] } }
end
+
+ def verify_rows_are_same_length(raw)
+ raw.transpose
+ rescue IndexError
+ raise ArgumentError, 'Rows must all be the same length'
+ end
end
end
end
diff --git a/lib/cucumber/core/test/doc_string.rb b/lib/cucumber/core/test/doc_string.rb
index b52410b2..ef3db070 100644
--- a/lib/cucumber/core/test/doc_string.rb
+++ b/lib/cucumber/core/test/doc_string.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'delegate'
+
module Cucumber
module Core
module Test
@@ -19,7 +20,6 @@ module Test
# example above, that would return: "I like\nCucumber sandwich"
#
# Note how the indentation from the source is stripped away.
- #
class DocString < SimpleDelegator
attr_reader :content_type, :content
@@ -29,47 +29,47 @@ def initialize(content, content_type)
super(@content)
end
- def describe_to(visitor, *)
- visitor.doc_string(self, *)
+ def ==(other)
+ return false if other.respond_to?(:content_type) && content_type != other.content_type
+ return content == other.to_str if other.respond_to?(:to_str)
+
+ false
end
def data_table?
false
end
- def doc_string?
- true
+ def describe_to(visitor, *)
+ visitor.doc_string(self, *)
end
- def map
- raise ArgumentError, 'No block given' unless block_given?
-
- new_content = yield content
- self.class.new(new_content, content_type)
+ def doc_string?
+ true
end
- def to_step_definition_arg
- self
+ def inspect
+ [
+ %(#<#{self.class}),
+ %( """#{content_type}),
+ %( #{@content}),
+ %( """>)
+ ].join("\n")
end
def lines_count
lines.count + 2
end
- def ==(other)
- return false if other.respond_to?(:content_type) && content_type != other.content_type
- return content == other.to_str if other.respond_to?(:to_str)
+ def map
+ raise ArgumentError, 'No block given' unless block_given?
- false
+ new_content = yield content
+ self.class.new(new_content, content_type)
end
- def inspect
- [
- %(#<#{self.class}),
- %( """#{content_type}),
- %( #{@content}),
- %( """>)
- ].join("\n")
+ def to_step_definition_arg
+ self
end
end
end
diff --git a/lib/cucumber/core/test/empty_multiline_argument.rb b/lib/cucumber/core/test/empty_multiline_argument.rb
index bae98703..aa64f62c 100644
--- a/lib/cucumber/core/test/empty_multiline_argument.rb
+++ b/lib/cucumber/core/test/empty_multiline_argument.rb
@@ -4,28 +4,28 @@ module Cucumber
module Core
module Test
class EmptyMultilineArgument
- def describe_to(*)
- self
- end
-
def data_table?
false
end
+ def describe_to(*)
+ self
+ end
+
def doc_string?
false
end
- def map
- self
+ def inspect
+ "#<#{self.class}>"
end
def lines_count
0
end
- def inspect
- "#<#{self.class}>"
+ def map
+ self
end
end
end
diff --git a/lib/cucumber/core/test/filters.rb b/lib/cucumber/core/test/filters.rb
index 45238dee..80b88177 100644
--- a/lib/cucumber/core/test/filters.rb
+++ b/lib/cucumber/core/test/filters.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-require 'cucumber/core/test/filters/locations_filter'
-require 'cucumber/core/test/filters/name_filter'
-require 'cucumber/core/test/filters/tag_filter'
+require_relative 'filters/locations_filter'
+require_relative 'filters/name_filter'
+require_relative 'filters/tag_filter'
diff --git a/lib/cucumber/core/test/hook_step.rb b/lib/cucumber/core/test/hook_step.rb
index 3667c5ae..cebafd42 100644
--- a/lib/cucumber/core/test/hook_step.rb
+++ b/lib/cucumber/core/test/hook_step.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'cucumber/core/test/step'
+require_relative 'step'
module Cucumber
module Core
diff --git a/lib/cucumber/core/test/location.rb b/lib/cucumber/core/test/location.rb
index c4f0e06e..ca98bb07 100644
--- a/lib/cucumber/core/test/location.rb
+++ b/lib/cucumber/core/test/location.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require 'forwardable'
-require 'cucumber/core/platform'
require 'set'
module Cucumber
diff --git a/lib/cucumber/core/test/step.rb b/lib/cucumber/core/test/step.rb
index 76786954..4a5a14d9 100644
--- a/lib/cucumber/core/test/step.rb
+++ b/lib/cucumber/core/test/step.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
-require 'cucumber/core/test/result'
-require 'cucumber/core/test/action'
-require 'cucumber/core/test/empty_multiline_argument'
+require_relative 'action'
+require_relative 'empty_multiline_argument'
module Cucumber
module Core
@@ -20,48 +19,48 @@ def initialize(id, text, location, multiline_arg = Test::EmptyMultilineArgument.
@action = action
end
- def describe_to(visitor, *)
- visitor.test_step(self, *)
+ def action_location
+ @action.location
end
- def hook?
- false
+ def backtrace_line
+ "#{location}:in `#{text}'"
end
- def skip(*)
- @action.skip(*)
+ def describe_to(visitor, *)
+ visitor.test_step(self, *)
end
def execute(*)
@action.execute(*)
end
- def with_action(action_location = nil, &)
- self.class.new(id, text, location, multiline_arg, Test::Action::Defined.new(action_location, &))
+ def hook?
+ false
end
- def with_unskippable_action(action_location = nil, &)
- self.class.new(id, text, location, multiline_arg, Test::Action::Unskippable.new(action_location, &))
+ def inspect
+ "#<#{self.class}: #{location}>"
end
- def backtrace_line
- "#{location}:in `#{text}'"
+ def matching_locations
+ [location.merge(multiline_arg)]
end
- def to_s
- text
+ def skip(*)
+ @action.skip(*)
end
- def action_location
- @action.location
+ def to_s
+ text
end
- def matching_locations
- [location.merge(multiline_arg)]
+ def with_action(action_location = nil, &)
+ self.class.new(id, text, location, multiline_arg, Test::Action::Defined.new(action_location, &))
end
- def inspect
- "#<#{self.class}: #{location}>"
+ def with_unskippable_action(action_location = nil, &)
+ self.class.new(id, text, location, multiline_arg, Test::Action::Unskippable.new(action_location, &))
end
end
end
diff --git a/lib/cucumber/core/test/tag.rb b/lib/cucumber/core/test/tag.rb
index e6e536ee..d857c25d 100644
--- a/lib/cucumber/core/test/tag.rb
+++ b/lib/cucumber/core/test/tag.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require_relative 'location'
+
module Cucumber
module Core
module Test
diff --git a/lib/cucumber/core/test/timer.rb b/lib/cucumber/core/test/timer.rb
index cc87c387..906de0ae 100644
--- a/lib/cucumber/core/test/timer.rb
+++ b/lib/cucumber/core/test/timer.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'cucumber/core/test/result'
+require_relative 'result'
module Cucumber
module Core
diff --git a/spec/cucumber/core/test/case_spec.rb b/spec/cucumber/core/test/case_spec.rb
index beb6a026..eb5febff 100644
--- a/spec/cucumber/core/test/case_spec.rb
+++ b/spec/cucumber/core/test/case_spec.rb
@@ -2,7 +2,6 @@
require 'cucumber/core'
require 'cucumber/core/gherkin/writer'
-require 'cucumber/core/platform'
require 'cucumber/core/test/case'
describe Cucumber::Core::Test::Case do
diff --git a/spec/cucumber/core_spec.rb b/spec/cucumber/core_spec.rb
index 4ff754ee..7cf2c6b6 100644
--- a/spec/cucumber/core_spec.rb
+++ b/spec/cucumber/core_spec.rb
@@ -6,7 +6,6 @@
require 'cucumber/core'
require 'cucumber/core/filter'
require 'cucumber/core/gherkin/writer'
-require 'cucumber/core/platform'
require 'cucumber/core/report/summary'
require 'cucumber/core/test/around_hook'
require 'cucumber/core/test/filters'