Skip to content

Detect incompatible use of `Struct.new` in Ruby 3.1 / 3.2

Problem

Since Ruby 3.2 (https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/) 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.

For example:

# Note no `keyword_init: true`.
Foo = Struct.new(:foo)

# Works in Ruby 3.2
Foo.new(foo: 42)
=> #<struct Foo foo=42>

# Fails in Ruby 3.1
Foo.new(foo: 42)
(irb):3: warning: Passing only keyword arguments to Struct#initialize will behave differently from Ruby 3.2. Please use a Hash literal like .new({k: v}) instead of .new(k: v).
=> #<struct Foo foo={:foo=>42}>

We need to add keyword_init: true as in Struct.new(:foo, keyword_init: true).

See:

Proposed

Detect if Struct.new is used without keyword_init: true but a hash is passed to Struct's instance.

Alternatively, wait until Ruby 3.1 is phased out.