This article touches on the issues but doesn't give a solution.
This started when I wanted to write a method and optionally pass it an argument which could be null or a ????
(proc
, lambda
, method
, block
, ???). Lets call it, for now, a block
because a block
works. The block
takes one required argument. An example of the method and a call to it would be:
#!/usr/bin/env ruby
def foo(&proc)
puts "before"
if proc
yield "passed to proc"
end
puts "after"
end
def add_message(s)
puts "from add_message #{s}"
end
foo { |s| add_message(s) }
foo
And the output is:
before
from add_message passed to proc
after
before
after
Great. But, what I'd like to do is be able to call foo
like this: foo(&:add_message)
. But I can't. Changing line 15 above I get:
before
./temp.rb:11:in `add_message': wrong number of arguments (given 0, expected 1) (ArgumentError)
from ./temp.rb:6:in `foo'
from ./temp.rb:15:in `<main>'
And, as the article above mentions, the arity is now -2. So, how do I write a simple method like add_message
that I can use with &:add_message
. OR!!! as is the case 99.99% of the time, please set me on the proper track on how to do this.
The problem is that Symbol#to_proc
does not create a proc that calls add_message
method correctly.
# `yield` will pass its arguments to proc
>> :add_message.to_proc.call('passed to proc')
# => ArgumentError
This calls 'passed to proc'.add_message
, because our method is defined in Object
it works when called on String
, however it is missing the required argument.
The solution is to make a proc that can accept the same arguments as add_message
method and pass them along to that method. We can use Object#method
that returns Method
object that implements its own to_proc
and has the same arity as the method.
>> method(:add_message).to_proc.arity
=> 1
>> method(:add_message).to_proc.call('passed to proc')
from add_message passed to proc
>> foo(&method(:add_message))
before
from add_message passed to proc
after