This question is about Ruby 2.2.
Let's say I have a method which takes positional and named arguments.
class Parent
def foo(positional, named1: "parent", named2: "parent")
puts positional.inspect
puts named1.inspect
puts named2.inspect
end
end
A subclass wants to both override some defaults, and add its own named arguments. How would I best do this? Ideally, it would not have to know details of the signature of the parent, in case the parent wants to add some optional positional arguments. My first attempt was this.
class Child < Parent
def foo(*args, named1: "child", named3: "child" )
super
end
end
But that blows up because the unknown named3:
is passed to the parent.
Child.new.foo({ this: 23 })
/Users/schwern/tmp/test.rb:10:in `foo': unknown keyword: this (ArgumentError)
from /Users/schwern/tmp/test.rb:15:in `<main>'
I tried explicitly passing arguments to super, but that didn't work either. It seems the first positional argument is getting treated as a named one.
class Child < Parent
def foo(*args, named1: "child", named3: "child" )
super(*args, named1: "child")
end
end
Child.new.foo({ this: 23 })
/Users/schwern/tmp/test.rb:10:in `foo': unknown keyword: this (ArgumentError)
from /Users/schwern/tmp/test.rb:15:in `<main>'
I can make Child know about the first positional parameter, that works...
class Child < Parent
def foo(arg, named1: "child", named3: "child" )
super(arg, named1: "child")
end
end
Child.new.foo({ this: 23 })
Parent.new.foo({ this: 23 })
{:this=>23}
"child"
"parent"
{:this=>23}
"parent"
"parent"
...until I pass in a named parameter.
Child.new.foo({ this: 23 }, named2: "caller")
Parent.new.foo({ this: 23 }, named2: "caller")
/Users/schwern/tmp/test.rb:10:in `foo': unknown keyword: named2 (ArgumentError)
from /Users/schwern/tmp/test.rb:15:in `<main>'
How do I make this work and retain the benefit of named parameter checks? I'm open to turning the positional parameter into a named one.