tags:

views:

55

answers:

5
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) }
+2  A: 

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)

ennuikiller
A: 

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.

Kathy Van Stone
A: 

In Ruby 1.9 you can write:

 p test_method &:upcase
JRL
+2  A: 

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
Topher Fangio
A: 

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.

khelll