The idiomatic way is to instead yield to a block.
def dummy_func(a, b, key:)
return a+b+key
end
def wrapper
puts yield
end
a = 4
b = 5
c = 6
wrapper do
dummy_func(a ,b, key: c)
end
Since the block is closure it can see all the same variables that the call to wrapper
can. Now there's no need to pass wrapper's arguments through.
If you really want to make your wrapper, you can do some introspection to determine what arguments the wrapped function takes.
def dummy_func(a, b=23, key: 42)
return a+b+key
end
def no_keys(a, b=23)
return a+b
end
def wrapper(func, *array, **hash)
method = self.method(func)
takes_array = method.parameters.any? { |p| [:req, :opt, :rest].include?(p[0]) }
takes_hash = method.parameters.any? { |p| [:keyreq, :key, :keyrest].include?(p[0]) }
if takes_array && takes_hash
self.send(func, *array, **hash)
elsif takes_array
self.send(func, *array)
elsif takes_hash
self.send(func, **hash)
else
self.send(func)
end
end
a = 4
b = 5
c = 6
puts wrapper(:dummy_func, a, b, key:c)
puts wrapper(:no_keys, a, b)
But this is quite a bit more complex and less flexible than yielding to a block. This also limits you to "functions" which are really methods on the main object (there are no function references in Ruby). That's why they're called with self.send
. Blocks require no assumptions about what is being wrapped.