From d64fcfebf60216bea2107e0fa6a4d9ce9c95cfe6 Mon Sep 17 00:00:00 2001 From: Aaron Pfeifer Date: Tue, 23 Dec 2025 15:06:36 -0500 Subject: [PATCH 1/6] Allow ruby version 4.0 in gemspec --- .github/workflows/ruby.yml | 2 +- flatware-cucumber.gemspec | 2 +- flatware-rspec.gemspec | 2 +- flatware.gemspec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 36d80ac..7ab2827 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: rspec-minor-versions: [6, 7, 8, 9, 10, 11, 12, 13] - ruby-versions: ["3.1", "3.2", "3.3", "3.4"] + ruby-versions: ["3.1", "3.2", "3.3", "3.4", "4.0"] env: BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rspec_3.${{ matrix.rspec-minor-versions }}.gemfile diff --git a/flatware-cucumber.gemspec b/flatware-cucumber.gemspec index 47b6694..c1d7a3a 100644 --- a/flatware-cucumber.gemspec +++ b/flatware-cucumber.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |s| ) s.homepage = 'http://github.com/briandunn/flatware' s.licenses = ['MIT'] - s.required_ruby_version = ['>= 2.6', '< 3.5'] + s.required_ruby_version = ['>= 2.6', '< 4.1'] s.require_paths = ['lib'] s.add_dependency %(cucumber), '~> 3.0' s.add_dependency %(flatware), Flatware::VERSION diff --git a/flatware-rspec.gemspec b/flatware-rspec.gemspec index d534c32..db5a2de 100644 --- a/flatware-rspec.gemspec +++ b/flatware-rspec.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| ) s.homepage = 'http://github.com/briandunn/flatware' s.licenses = ['MIT'] - s.required_ruby_version = ['>= 2.6', '< 3.5'] + s.required_ruby_version = ['>= 2.6', '< 4.1'] s.require_paths = ['lib'] s.add_dependency %(flatware), Flatware::VERSION s.add_dependency %(rspec), '>= 3.6' diff --git a/flatware.gemspec b/flatware.gemspec index 20121be..713dd3c 100644 --- a/flatware.gemspec +++ b/flatware.gemspec @@ -26,7 +26,7 @@ Gem::Specification.new do |s| s.homepage = 'http://github.com/briandunn/flatware' s.licenses = ['MIT'] - s.required_ruby_version = ['>= 2.6', '< 3.5'] + s.required_ruby_version = ['>= 2.6', '< 4.1'] s.require_paths = ['lib'] s.executables = ['flatware'] s.add_dependency %(drb) From ab5a9e87662ccf934d370a39e09592ac22bacc33 Mon Sep 17 00:00:00 2001 From: Aaron Pfeifer Date: Fri, 2 Jan 2026 14:00:54 -0500 Subject: [PATCH 2/6] Add missing gem dependencies for Ruby 4 --- flatware-cucumber.gemspec | 1 + flatware.gemspec | 2 ++ 2 files changed, 3 insertions(+) diff --git a/flatware-cucumber.gemspec b/flatware-cucumber.gemspec index c1d7a3a..cc5c474 100644 --- a/flatware-cucumber.gemspec +++ b/flatware-cucumber.gemspec @@ -24,5 +24,6 @@ Gem::Specification.new do |s| s.require_paths = ['lib'] s.add_dependency %(cucumber), '~> 3.0' s.add_dependency %(flatware), Flatware::VERSION + s.add_dependency %(ostruct) # s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/flatware.gemspec b/flatware.gemspec index 713dd3c..72eec68 100644 --- a/flatware.gemspec +++ b/flatware.gemspec @@ -29,7 +29,9 @@ Gem::Specification.new do |s| s.required_ruby_version = ['>= 2.6', '< 4.1'] s.require_paths = ['lib'] s.executables = ['flatware'] + s.add_dependency %(benchmark) s.add_dependency %(drb) + s.add_dependency %(logger) s.add_dependency %(thor), '< 2.0' # s.metadata['rubygems_mfa_required'] = 'true' end From b3aa6e305be88530ea056f0a1769bf652647df81 Mon Sep 17 00:00:00 2001 From: Aaron Pfeifer Date: Tue, 23 Dec 2025 15:51:58 -0500 Subject: [PATCH 3/6] Exclude certain ruby version / rspec version combinations --- .github/workflows/ruby.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 7ab2827..52cc588 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,6 +21,11 @@ jobs: matrix: rspec-minor-versions: [6, 7, 8, 9, 10, 11, 12, 13] ruby-versions: ["3.1", "3.2", "3.3", "3.4", "4.0"] + exclude: + - ruby-versions: 4.0 + rspec-minor-versions: 6 + - ruby-versions: 4.0 + rspec-minor-versions: 7 env: BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rspec_3.${{ matrix.rspec-minor-versions }}.gemfile From 7fcb08407da4a4a60a18f44b95a9d93cddfc97a3 Mon Sep 17 00:00:00 2001 From: Aaron Pfeifer Date: Fri, 2 Jan 2026 13:22:40 -0500 Subject: [PATCH 4/6] Bump minimum cucumber version to 10.x in order to be compatible with Ruby 4 --- Rakefile | 2 +- flatware-cucumber.gemspec | 2 +- lib/flatware/cucumber.rb | 13 ++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index cbf8929..d82c101 100644 --- a/Rakefile +++ b/Rakefile @@ -19,7 +19,7 @@ end RuboCop::RakeTask.new :lint Cucumber::Rake::Task.new :cucumber do |task| - task.cucumber_opts = ['--tags', 'not @wip'] + task.cucumber_opts = ['--tags', 'not @wip', '--publish-quiet'] task.cucumber_opts += %w[-f progress] unless ENV['TRAVIS'] task.fork = false end diff --git a/flatware-cucumber.gemspec b/flatware-cucumber.gemspec index cc5c474..6f81999 100644 --- a/flatware-cucumber.gemspec +++ b/flatware-cucumber.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |s| s.licenses = ['MIT'] s.required_ruby_version = ['>= 2.6', '< 4.1'] s.require_paths = ['lib'] - s.add_dependency %(cucumber), '~> 3.0' + s.add_dependency %(cucumber), '>= 10.0' s.add_dependency %(flatware), Flatware::VERSION s.add_dependency %(ostruct) # s.metadata['rubygems_mfa_required'] = 'true' diff --git a/lib/flatware/cucumber.rb b/lib/flatware/cucumber.rb index e821905..18c800b 100644 --- a/lib/flatware/cucumber.rb +++ b/lib/flatware/cucumber.rb @@ -35,12 +35,23 @@ def feature_files def configure(args, out_stream = $stdout, error_stream = $stderr) raw_args = args.dup cli_config = ::Cucumber::Cli::Configuration.new(out_stream, error_stream) - cli_config.parse! args + %w[--format Flatware::Cucumber::Formatter] + cli_config.parse! args + %w[--format Flatware::Cucumber::Formatter --publish-quiet] cucumber_config = ::Cucumber::Configuration.new cli_config Config.new cucumber_config, raw_args end def run(feature_files, options) + # TODO: This will eventually stop working. This ensures step definitions are evaluated on each execution + # by using `load` instead of once per Ruby runtime using `require`. + # + # If we use the same runtime object and reconfigure it on each execution here, the wrong feature files will + # be evaluated since their memoized. Unfortunately, this means there's no straightforward way to both ensure + # step definitions are available on every runtime *and* also ensure Cucumber isn't memoizing the feature files + # to run. + # + # For now, the legacy autoloader is the only option to keep everything working properly. + ::Cucumber.use_legacy_autoloader ||= true + runtime(Array(feature_files) + options).run! end From 2033681c0b9b68fe7653448bbe116cd605ccf0b3 Mon Sep 17 00:00:00 2001 From: Aaron Pfeifer Date: Fri, 2 Jan 2026 14:01:14 -0500 Subject: [PATCH 5/6] Use newer versions of the aruba gem for Ruby 4 compatibility --- Gemfile | 2 +- features/step_definitions/flatware_steps.rb | 4 ++-- gemfiles/rspec_3.10.gemfile | 2 +- gemfiles/rspec_3.11.gemfile | 2 +- gemfiles/rspec_3.12.gemfile | 2 +- gemfiles/rspec_3.13.gemfile | 2 +- gemfiles/rspec_3.6.gemfile | 2 +- gemfiles/rspec_3.7.gemfile | 2 +- gemfiles/rspec_3.8.gemfile | 2 +- gemfiles/rspec_3.9.gemfile | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index aec2f52..2824f9d 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ gemspec name: 'flatware-cucumber' group :development do gem 'appraisal' - gem 'aruba', '~> 0.14' + gem 'aruba' gem 'logger' gem 'ostruct' gem 'pry' diff --git a/features/step_definitions/flatware_steps.rb b/features/step_definitions/flatware_steps.rb index 69711f1..5edd39d 100644 --- a/features/step_definitions/flatware_steps.rb +++ b/features/step_definitions/flatware_steps.rb @@ -77,7 +77,7 @@ def duration(&block) command = ['flatware', args, '-w', max_workers].flatten.compact.join(' ') @duration = duration do - run_command_and_stop(command, fail_on_exit: false) + run_command_and_stop(command, fail_on_error: false) end end @@ -113,7 +113,7 @@ def duration(&block) Then 'the output contains a backtrace' do trace = <<-TXT.gsub(/^ +/, '') - features/flunk.feature:4:in `Given flunk' + features/flunk.feature:4:in `flunk' TXT expect(flatware_process).to have_output Regexp.new Regexp.escape trace diff --git a/gemfiles/rspec_3.10.gemfile b/gemfiles/rspec_3.10.gemfile index 0b27a9e..186cb79 100644 --- a/gemfiles/rspec_3.10.gemfile +++ b/gemfiles/rspec_3.10.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.10.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.11.gemfile b/gemfiles/rspec_3.11.gemfile index 05e24b2..9f3c0e0 100644 --- a/gemfiles/rspec_3.11.gemfile +++ b/gemfiles/rspec_3.11.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.11.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.12.gemfile b/gemfiles/rspec_3.12.gemfile index 6264d6f..ed81aea 100644 --- a/gemfiles/rspec_3.12.gemfile +++ b/gemfiles/rspec_3.12.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.12.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.13.gemfile b/gemfiles/rspec_3.13.gemfile index 9a4a683..e8648d4 100644 --- a/gemfiles/rspec_3.13.gemfile +++ b/gemfiles/rspec_3.13.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.13.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.6.gemfile b/gemfiles/rspec_3.6.gemfile index 7283dd8..ea2e2bf 100644 --- a/gemfiles/rspec_3.6.gemfile +++ b/gemfiles/rspec_3.6.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.6.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.7.gemfile b/gemfiles/rspec_3.7.gemfile index 9fcc482..411db5e 100644 --- a/gemfiles/rspec_3.7.gemfile +++ b/gemfiles/rspec_3.7.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.7.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.8.gemfile b/gemfiles/rspec_3.8.gemfile index a55a9bf..c9f5f97 100644 --- a/gemfiles/rspec_3.8.gemfile +++ b/gemfiles/rspec_3.8.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.8.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" diff --git a/gemfiles/rspec_3.9.gemfile b/gemfiles/rspec_3.9.gemfile index 559951b..d60226a 100644 --- a/gemfiles/rspec_3.9.gemfile +++ b/gemfiles/rspec_3.9.gemfile @@ -6,7 +6,7 @@ gem "rspec", "3.9.0" group :development do gem "appraisal" - gem "aruba", "~> 0.14" + gem "aruba" gem "pry" gem "racc" gem "rake" From 16dbf5b78576df091fb5a165af12509183f448bb Mon Sep 17 00:00:00 2001 From: Aaron Pfeifer Date: Tue, 23 Dec 2025 15:33:59 -0500 Subject: [PATCH 6/6] Fix rubocop failures --- .rubocop.yml | 3 ++ .../cucumber/formatters/console/summary.rb | 1 + lib/flatware/pid.rb | 6 ++-- lib/flatware/rspec/formatters/console.rb | 12 +++---- lib/flatware/rspec/job_builder.rb | 36 ++++++++++--------- lib/flatware/sink.rb | 4 +-- spec/flatware/sink/signal_spec.rb | 2 +- 7 files changed, 35 insertions(+), 29 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index eff9a44..09f78a6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -25,6 +25,9 @@ Style/FrozenStringLiteralComment: Naming/FileName: Exclude: - lib/flatware-*.rb +Naming/PredicateMethod: + Exclude: + - lib/flatware/sink.rb Style/Documentation: Enabled: false Metrics/BlockLength: diff --git a/lib/flatware/cucumber/formatters/console/summary.rb b/lib/flatware/cucumber/formatters/console/summary.rb index 57ea023..bc5c571 100644 --- a/lib/flatware/cucumber/formatters/console/summary.rb +++ b/lib/flatware/cucumber/formatters/console/summary.rb @@ -7,6 +7,7 @@ module Formatters class Console class Summary include ::Cucumber::Formatter::Console + attr_reader :io, :steps, :scenarios def initialize(steps, scenarios = [], io = StringIO.new) diff --git a/lib/flatware/pid.rb b/lib/flatware/pid.rb index 7914963..d478380 100644 --- a/lib/flatware/pid.rb +++ b/lib/flatware/pid.rb @@ -27,9 +27,9 @@ def self.ps .popen(['ps', *args]) .readlines .map do |row| - fields = row.strip.split(/\s+/, 4) - new(*fields.take(3).map(&:to_i), fields.last) - end + fields = row.strip.split(/\s+/, 4) + new(*fields.take(3).map(&:to_i), fields.last) + end end def pids_of_group(group_pid) diff --git a/lib/flatware/rspec/formatters/console.rb b/lib/flatware/rspec/formatters/console.rb index 5429a77..154b587 100644 --- a/lib/flatware/rspec/formatters/console.rb +++ b/lib/flatware/rspec/formatters/console.rb @@ -63,12 +63,12 @@ def spec_list(remaining) remaining .flat_map(&:id).sort.each_with_index .map do |example, index| - format( - '%4d) %s', - index: index.next, - example: example - ) - end.join("\n") + format( + '%4d) %s', + index: index.next, + example: example + ) + end.join("\n") end def colorizer diff --git a/lib/flatware/rspec/job_builder.rb b/lib/flatware/rspec/job_builder.rb index 2691aef..5d3c110 100644 --- a/lib/flatware/rspec/job_builder.rb +++ b/lib/flatware/rspec/job_builder.rb @@ -9,6 +9,7 @@ module RSpec # and attempts to ballence the jobs accordingly. class JobBuilder extend Forwardable + attr_reader :args, :workers, :configuration def_delegators( @@ -54,12 +55,12 @@ def timed_and_untimed_files(seconds_per_file) files_to_run .map(&method(:normalize_path)) .reduce([[], []]) do |(timed, untimed), file| - if (time = seconds_per_file[file]) - [timed + [[file, time]], untimed] - else - [timed, untimed + [file]] + if (time = seconds_per_file[file]) + [timed + [[file, time]], untimed] + else + [timed, untimed + [file]] + end end - end end def normalize_path(path) @@ -73,14 +74,15 @@ def load_persisted_example_statuses end def sum_seconds(statuses) - statuses.select(&passing) - .map { |example| parse_example(**example) } - .reduce({}) do |times, example| - times.merge( - example.fetch(:file_name) => example.fetch(:seconds) - ) do |_, old = 0, new| - old + new - end + statuses + .select(&passing) + .map { |example| parse_example(**example) } + .reduce({}) do |times, example| + times.merge( + example.fetch(:file_name) => example.fetch(:seconds) + ) do |_, old = 0, new| + old + new + end end end @@ -109,10 +111,10 @@ def balance_by(count, items, &block) .sort_by(&block) .reverse .each do |entry| - groups.min_by do |group| - group.map(&block).reduce(:+) || 0 - end.push(entry) - end + groups.min_by do |group| + group.map(&block).reduce(:+) || 0 + end.push(entry) + end end end end diff --git a/lib/flatware/sink.rb b/lib/flatware/sink.rb index 2788487..2227ac8 100644 --- a/lib/flatware/sink.rb +++ b/lib/flatware/sink.rb @@ -117,8 +117,8 @@ def group_jobs(jobs, worker_count) .with_index { |_, i| i % worker_count } .values .map do |job_group| - Job.new(job_group.map(&:id).flatten, jobs.first.args) - end + Job.new(job_group.map(&:id).flatten, jobs.first.args) + end end end end diff --git a/spec/flatware/sink/signal_spec.rb b/spec/flatware/sink/signal_spec.rb index bc62baa..2d8e21d 100644 --- a/spec/flatware/sink/signal_spec.rb +++ b/spec/flatware/sink/signal_spec.rb @@ -53,7 +53,7 @@ def send_signal(signal) end it 'tells the formatter to emit the signal message' do - expect(messages).to match([include(expected_message), 'done.']) + expect(messages).to match([match(expected_message), 'done.']) end it 'calls on_interrupt' do