A notable change has been announced for Ruby 3 for which deprecation warning has been added in Ruby 2.7. Ruby 2.7 deprecated automatic conversion of keyword arguments and positional arguments. This conversion will be completely removed in Ruby 3.

Ruby 2.7 NEWS has listed the spec of keyword arguments for Ruby 3.0. We will take the examples mentioned there and for each scenario we will look into how we can fix them in the existing codebase.

Scenario 1

When method definition accepts keyword arguments as the last argument.

def sum(a: 0, b: 0)
  a + b
end

Passing exact keyword arguments in a method call is acceptable, but in applications we usually pass a hash to a method call.

sum(a: 2, b: 4) # OK

sum({ a: 2, b: 4 }) # Warned

In this case, we can add a double splat operator to the hash to avoid deprecation warning.

sum(**{ a: 2, b: 4 }) # OK

Scenario 2

When method call passes keyword arguments but does not pass enough required positional arguments.

If the number of positional arguments doesn’t match with method definition, then keyword arguments passed in method call will be considered as the last positional argument to the method.

def sum(num, x: 0)
  num.values.sum + x
end
sum(a: 2, b: 4) # Warned

sum(a: 2, b: 4, x: 6) # Warned

To avoid deprecation warning and for code to be compatible with Ruby 3, we should pass hash instead of keyword arguments in method call.

sum({ a: 2, b: 4 }) # OK

sum({ a: 2, b: 4}, x: 6) # OK

Scenario 3

When a method accepts a hash and keyword arguments but method call passes only hash or keyword arguments.

If a method arguments are a mix of symbol keys and non-symbol keys, and the method definition accepts either one of them then Ruby splits the keyword arguments but also raises a warning.

def sum(num={}, x: 0)
  num.values.sum + x
end
sum("x" => 2, x: 4) # Warned

sum(x: 2, "x" => 4) # Warned

To fix this warning, we should pass hash separately as defined in the method definition.

sum({ "x" => 4 }, x: 2) # OK

Scenario 4

When an empty hash with double splat operator is passed to a method that doesn’t accept keyword arguments.

Passing keyword arguments using double splat operator to a method that doesn’t accept keyword argument will send empty hash similar to earlier version of Ruby but will raise a warning.

def sum(num)
  num.values.sum
end
numbers = {}
sum(**numbers) # Warned

To avoid this warning, we should change method call to pass hash instead of using double splat operator.

numbers = {}
sum(numbers) # OK

Added support for non-symbol keys

In Ruby 2.6.0, support for non-symbol keys in method call was removed. It is added back in Ruby 2.7. When method accepts arbitrary keyword arguments using double splat operator then non-symbol keys can also be passed.

def sum(**num)
  num.values.sum
end
ruby 2.6.5
sum("x" => 4, "y" => 3)
=> ArgumentError (wrong number of arguments (given 1, expected 0))

sum(x: 4, y: 3)
=> 7
ruby 2.7.0
sum("x" => 4, "y" => 3)
=> 7

sum(x: 4, y: 3)
=> 7

Added support for **nil

Ruby 2.7 added support for **nil to explicitly mention if a method doesn’t accept any keyword arguments in method call.

def sum(a, b, **nil)
  a + b
end

sum(2, 3, x: 4)
=> ArgumentError (no keywords accepted)

To suppress above deprecation warnings we can use -W:no-deprecated option.

In conclusion, Ruby 2.7 has worked big steps towards changing specification of keyword arguments which will be completely changed in Ruby 3.

For more information on discussion, code changes and official documentation, please head to Feature #14183 discussion, pull request and NEWS release.