For example:
class Person < ApplicationRecord
validates :name, presence: true
end
Is "presence: true" a hash with key "presence" and value "true"? Or is it a keyword-argument?
How does one know, what the second argument is?
How does one handle such cases in general? Or isn't it relevant and I shouldn't bother?
Or isn't it relevant and I shouldn't bother?
In general, it's not relevant unless you're writing methods that need to distinguish between positional hashes and keyword arguments explicitly. Ruby often treats them similarly, especially if you're just passing them around — but there is a difference under the hood.
They’re both just Hashes
at runtime, but Ruby differentiates between positional hashes and keyword arguments in method signatures. So if you're inspecting method arity, introspecting code, or using advanced metaprogramming, it is relevant — otherwise, you probably don’t need to worry about it.
(Tested in Ruby 3.0) Let’s look at a small example:
class TestArgs
def call(opts = {}, opts_kwargs: {})
puts "Keyword argument: #{opts_kwargs}"
puts "Options: #{opts.inspect}"
puts "opts_kwargs.class => #{opts_kwargs.class}"
puts "opts.class => #{opts.class}"
end
end
test_args = TestArgs.new
test_args.call({ keyword_argument: 'bar' }, opts_kwargs: { keyword_argument: 'baz' })
puts TestArgs.instance_method(:call).parameters.inspect
Output
Keyword argument: {:keyword_argument=>"baz"}
Options: {:keyword_argument=>"bar"}
opts_kwargs.class => Hash
opts.class => Hash
[[:opt, :opts], [:key, :opts_kwargs]]
Both opts
and opts_kwargs
are Hash
objects — so at runtime, they're indistinguishable by class.
But Method#parameters
reveals how Ruby interprets them at the method definition level:
:opt
marks a positional argument (with default),:key
marks a keyword argument (with default).So while they may look and behave similarly, Ruby keeps track of them differently in the method signature.