How to pass optional named arguments in Ruby 2.0
It's not entirely clear why you want to know if the argument was provided or not. The most useful reason to know, is because you want to require one of your optional arguments. If that's the reason, then starting with Ruby 2.1, you can get what you want.
def foo(a:,b:nil,c:3)
[a, b, c]
end
foo a: 1, b: 2, c: 3
#=> [1, 2, 3]
foo a: 1, b: 2
#=> [1, 2, 3]
foo a: 1
#=> [1, nil, 3]
foo
#ArgumentError: missing keyword: a
I would assume from you example that you are not using name
in foo
but want to pass it along.
You should use the catch all for named arguments instead:
def foo(**named)
# …
bar(**named)
end
def bar(name: 'unknown')
# …
puts name
end
foo # => 'unknown'
foo(name: 'baz') # => 'baz'
Note that this not interfere with other arguments (named or not), so you if you had other arguments for foo
:
def foo(what, other: 42, **named)
You can use an "undefined" value as the default to tell it apart from a nil:
Undefined = Object.new.freeze
def foo(a: Undefined)
puts a
end
foo(a: nil) # => "nil"
foo # => "#<Object:0x000056004b29a058>"
If you use dry-rb, then you can use Dry::Core::Constants::Undefined
(source), which provides a few extras:
Undefined = Dry::Core::Constants::Undefined
def foo(a: Undefined)
puts a
end
foo(a: nil) # => "nil"
foo # => "Undefined"
Probably the best way to go would be:
def bar(name: nil)
name ||= 'unknown'
puts name
end