Detect incompatible use of `Struct.new` in specs
What does this MR do and why?
This commit patches Struct.new in specs when keyword_init is missing
and a Hash passed.
Reason: Since Ruby 3.2 Struct supports kwargs by default so
keyword_init: true is no longer required. We are running Ruby 3.2 in
MRs and Ruby 3.1 on master so occasionally master is broken due to this
incompatibility.
This slows down creation of Struct objects in specs by factor 3.
Closes #474743 (closed).
Refs !161677 (comment 2086365521)
How to set up and validate locally
- Apply patch from !161677 (closed) (for commit !161677 (64e0e441))
- Via:
curl -sG https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161677.patch | git apply
- Via:
- Run a spec which uses incompatible
Structuse-
bin/rspec spec/requests/api/repositories_spec.rb:197- to useRepoHelpers#sample_blob
-
- See the failure caught by
StructWithKwargs:
Failures:
1) API::Repositories GET /projects/:id/repository/blobs/:sha when authenticated as a developer behaves like repository blob returns blob attributes as json
Failure/Error:
raise <<~MESSAGE
Passing only keyword arguments to #{self.class}#initialize will behave differently from Ruby 3.2. Please pass `keyword_init: true` to `Struct` constructor or use a Hash literal like .new({k: v}) instead of .new(k: v).
MESSAGE
RuntimeError:
Passing only keyword arguments to RepoHelpers::BlobStruct#initialize will behave differently from Ruby 3.2. Please pass `keyword_init: true` to `Struct` constructor or use a Hash literal like .new({k: v}) instead of .new(k: v).
- Fix
RepoHelpers#BlobStructby addingkeyword_init: true - Re-ran the spec
✅
Performance
This patch slows down the creation of Struct objects (not classes!) in specs by factor 3:
$ STRUCT_WITH_KWARGS=1 ruby foo.rb
Warming up --------------------------------------
with Y.new 249.948k i/100ms
Calculating -------------------------------------
with Y.new 2.515M (± 4.2%) i/s - 12.747M in 5.078006s
Comparison:
without Y.new: 7824852.3 i/s
with Y.new: 2515205.9 i/s - 3.11x slower
The script
# frozen_string_literal: true
require 'benchmark/ips'
require_relative 'spec/support/struct_with_kwargs' if ENV['STRUCT_WITH_KWARGS']
label = ENV['STRUCT_WITH_KWARGS'] ? 'with' : 'without'
X = Struct.new(:a)
Benchmark.ips do |x|
x.report "#{label} Y.new" do
X.new(1)
end
x.save! 'tmp_results'
x.compare!
end
Run twice:
ruby foo.rb
STRUCT_WITH_KWARGS=1 ruby foo.rb
Edited by Peter Leitzen