Ruby introduced deprecation warnings in 2.71 in preparations for Ruby 3’s incompatibility changes to keyword arguments.
Let’s recap for what we have now.
Positional arguments, optional arguments, and keyword arguments.
def positional_method(a); end
def optional_method(b = {}); end
def keyword_argument_method(c: nil, r:); end
def optional_splat(*d); end
def optional_double_splat(**e); end
a
is an positional argument.
b
is an optional argument, defaults to empty hash.
c
is an keyword argument, defaults to nil
.
r
is a required keyword argument.
d
is an optional splat argument.
e
is an optional double splat argument.
*
is called splat, and **
is called double splat. You can use these operators in method signatures and method calls:
def a_method(*args); end
def another_method(**args); end
In method signatures
Single splat packs the argument into Array.
Double splat packs the argument into Hash.
In method calls
Single splat unpacks the argument from Array.
Double splat unpacks the argument from Hash.
Before Ruby 2, we use options Hash to achieve keyword arguments, and Hash#fetch
for required keyword arguments:
def ruby_19_translate(options = {})
puts options.fetch(:key, "en")
end
def ruby_19_required_translate(options = {})
puts options.fetch(:key)
end
define_method(:ruby_19_block_translate) do |options = {}|
puts options.fetch(:key, "en")
end
define_method(:ruby_19_block_required_translate) do |options = {}|
puts options.fetch(:key)
end
ruby_19_translate # => "en"
ruby_19_required_translate # KeyError: key not found: :key
ruby_19_block_translate # => "en"
ruby_19_block_translate(key: "es") # => "es"
ruby_19_block_required_translate # KeyError: key not found: :key
ruby_19_block_required_translate(key: "es") # => "es"
Keyword arguments first introduced in Ruby 2.0. Block keyword arguments also introduced:
def translate(key: "en")
puts key
end
def required_translate(key:)
puts key
end
define_method(:block_translate) do |key: 'en'|
puts key
end
define_method(:block_required_translate) do |key:|
puts key
end
translate # => "en"
required_translate # ArgumentError: missing keyword: :key
required_translate(key: "es") # => "es"
block_translate # => "en"
block_translate(key: "es") # => "es"
block_required_translate # ArgumentError: missing keyword: :key
block_required_translate(key: "es") # => "es"
Required keyword argument added in Ruby 2.1.
If the last argument of a method call is a Hash, Ruby < 2.7 will automatically convert to Keyword Arguments.
The abovementioned automatic conversion will stop. Emit a warning in Ruby 2.7, which will eventually break your app in Ruby 3.
Upgrade to Ruby 2.7 and fix the places rely on such automatic conversion.
Be explicit.
Wrap argument in {}
if you want to pass in a hash:
translate({ key: value })
# instead of
translate(key: value)
Prefix argument with **
if you want to pass in keywords:
keywords = { throw: true, raise: false }
translate(**keywords)
# instead of
translate(keywords)
Use double splat keyword arguments instead of options hash:
def good(**kwargs)
kwargs
end
# instead of
def old(kwargs = {})
kwargs
end
If you can’t convert, use ruby2_keywords
to keep the old behavior first.
- Turn off all warnings (not recommended)
- Try not to use the compatibility gem: ruby2_keywords
- Upgrade to Ruby 2.7 and fix all warnings for gems you’re using
- Fix all occurrences that rely on auto conversion
Hope this helps! Thanks for reading.