yield: why can't i write: p test_method { i.upcase }
Question
def test_method
["a", "b", "c"].map {|i| yield(i) }
end
If I call test_method like this:
p test_method {|i| i.upcase }
# => ["A", "B", "C"]
Why do I need the {|i|} inside the block, instead of just saying this:
p test_method { i.upcase }
The reason I think so is because when yield is called in test_method, we already have an {|i|}
["a", "b", "c"].map {|i| yield(i) }
Solution
The block needs a parameterized value to pass to the upcase method. It can be looked at this way: If you leave out the |i| in the block it has no way of "catching" the value yielded (i in test_method)
OTHER TIPS
If you are coming from Groovy background where they have an implicit iterator, or even from Scala where you can do without this |i| using partial functions, then you might find it a logical question, however, at the current moment the best you can do in Ruby 1.9 or even inside Rails, is to use the Symbol#to_block method like JRL mentioned:
p test_method &:upcase
So just add the &: before the method name.
In Ruby 1.9 you can write:
p test_method &:upcase
As ennuikiller said, you must define what you wish to name the variable(s) that is passed back from the yield
statement. This has to do with a variable's scope. The scope inside of the block that you pass to test_method
does not know about the i
variable. You can actually call this whatever you wish.
For instance, you could do the following:
def test_method
["a", "b", "c"].map { |i| yield(i) }
end
p test_method { |some_variable_name| some_variable_name.upcase }
Just because the test method knows about it, it does not means that the block that you pass to the test method will know about it.
Edit 1: To give a little more information, you can redefine test_method
as follows if it makes it a little bit more clear:
def test_method(&block)
if not block.nil?
["a", "b", "c"].map { |i| yield(i) }
end
end
At the time you call
p test_method {|i| i.upcase}
The |i|
used in the method definition is not visible (its scope is solely within the {}
.
In particular you are building a block that takes a single variable, and to build that block you must specify what that variable is. Note that
p test_method {|j| j.upcase}
is also valid.