wwang
wwang

Reputation: 69

Issue with define_method in Ruby 3.0

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?

Upvotes: 2

Views: 897

Answers (1)

Marlin Pierce
Marlin Pierce

Reputation: 10099

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.

Upvotes: 5

Related Questions