ArgumentError when upgrading from Ruby 2.7 to 3.0 - related to separation of positional and keyword arguments?

1k Views Asked by At

I am trying to upgrade gems from ruby 2.7.0 to 3.0.0. I have tried to read and plan ahead for what roadblocks I'd hit, like the Separation of positional and keyword arguments.

I have updated two gems smoothly, but I have started to upgrade a third and, while testing the 3.0 update with RSpec, have run into the following error:

ArgumentError:
        wrong number of arguments (given 1, expected 0; required keyword: children)

I am trying it instantiate a Class through a Factory. The stack trace is pointing back to the arguments of this function:

      # rubocop:disable Style/KeywordParametersOrder
      def initialize(parent_obj: nil, children:, **attributes)
        @attributes = attributes
        @parent = parent_obj
        @children_json = children
      end
      # rubocop:enable Style/KeywordParametersOrder

Though I don't think it is significant, I have included the rubocop dis/enable lines just in case they are important.

The Factory is calling the class in this fashion:

data = {:some_data=>"foo", :some_name=>"bar", :children=>[]}
Long::Class::Name.new(data)

Now, when I pry into the code between data and Long::Class::Name.new(data) and instantiate my own Long::Class::Name like below:

Long::Class::Name.new(children: children, attributes: data)

it results in a successful creation without the ArgumentError.

I think to myself, "Cool, I'll just update the Factory's Class call to this new format and re-run the tests." After doing this, I am still getting the same ArgumentError as above.

I believe this is an issue with positional/keyword arguments like I linked above, but I am having trouble seeing how I can correct this. Besides the link above, I have also looked into Ruby 3 Keyword Arguments, as well as Hash and Keyword Coercion and Ruby 3 Changes. I believe I am facing the "Unforeseen Consequences" portion of that last link.

I have also looked at this Stack Overflow issue about ArgumentError after updating from Ruby 2.7 to Ruby 3.0 and tried to understand how I could use the first portion of the first answer to help me with my issue (disregarding the Update related to a PR).

Any thoughts on how can I dispel or work around this error? I have many gems I need to update and I am sure this will not be the last time I see this error. Any help would be greatly appreciated. Let me know if more information is needed.

1

There are 1 best solutions below

2
On

When you do this…

data = {:some_data=>"foo", :some_name=>"bar", :children=>[]}
Long::Class::Name.new(data)

…you are calling the method with one positional argument (a hash containing the keys :some_data, :some_name, and :children) and no keyword argument.

If you instead were to call it like this…

Long::Class::Name.new(**data)

…you would be calling it with no positional argument and three keyword arguments.

This is called the "double splat" and was introduced for exactly your usecase, turning a hash into keyword arguments.