Issue with define_method in Ruby 3.0

800 views Asked by At

I'm working on an upgrade from Ruby 2.7 to 3.0 and faced an issue with the keyword arguments change.

Previously we used define_method in our code for some purposes. However, with the keyword arguments change, it can no longer handle an array of arguments properly anymore.

class Foo
  def test(a: 1, b: 2)
    puts a
    puts b
  end

  old_method = instance_method(:test)

  define_method(:test) do |*args, &block|
    old_method.bind(self).call(*args, &block)
  end
end

Foo.new.test(a: 1)

This will raise wrong number of arguments (given 1, expected 0) (ArgumentError). And it previously worked in Ruby 2.7. Is there anything we can do to get the *args to work again?

1

There are 1 answers

3
Marlin Pierce On

Try

  define_method(:test) do |*args, **kwords, &block|
    old_method.bind(self).call(*args, **kwords, &block)
  end

Ruby 3.0 is changing the handling of method arguments which give a deprecation warning in 2.7. There is some unexpected behavior including a keywords in a *args array. This had to be done using a hash and there needs to be more of a distinction between a hash argument and keywords. So in ruby 3.x you need to capture an arbitrary collection of keywords in a double splat because they cannot be included in the splat argument.

Mostly my understanding is shaky but I read this as an explicit example in the explanation of the changed to the arguments in the release notes for ruby 3.0.