tags:

views:

253

answers:

4
class MyClass
  def test
    ...
  end
end

tmp = MyClass.new
tmp.test do |t|
  "here" 
end

Why am I getting the error

multiple values for a block parameter (0 for 1)
+1  A: 

if test is defined with a yield statement, when that statement is reached and if there is a parameter on the yield statement, that parameter will be put into the block variable t. Thus if you have:

def test
.....
yield x
......
end 

then x will be the value of t when yield is executed.

ennuikiller
How do I access "here" within the test method?
Bob
You can't... test can only pass something to the block, not the other way around. In order to pass "here" to the test method, you should modify the test method to take another argument, and put "here" as the corresponding actual parameter in the method call.
Platinum Azure
+3  A: 

Here is a slightly longer example, based on your code:

class MyClass
  def test
    yield self
  end

  def my_own_puts s
    puts s
  end

end

tmp = MyClass.new
tmp.test do |t|
  t.my_own_puts "here"
end

Running this code will output "here".

What is happening is there is a method test that can take a block of code, so you can call it with the do .. end syntax. Because it is passing an arg to yield, that arg is available to the block, so you give this to the block using the do |some_arg_name| ... end syntax.

The yield is where the block gets executed in the test method, and in this case I to yield I pass in self. Since the block now has access to self (an instance of MyClass), the block can call the my_own_puts method on it, and print out "here".

Andrew Kuklewicz
Unfortunately I need to keep the calling snippet of code the same as in my original example, any other ideas?
Bob
If you don't pass in an arg to the yield, that is the error you will get. You can't use the "do |t|" if there is no "t" passed in from the yield.
Andrew Kuklewicz
+1  A: 

With your help, I was able to get the code working like this

class MyClass
  def test
    a = yield self
    puts a
  end
end

tmp = MyClass.new
tmp.test do |t|
  "here" 
end

Thanks, I had to tweak your code a bit but it works the way I wanted to now.

Bob
A: 

Passing a block to a function (as Bob shows in his answer) is overkill in this case. If you are reading in a string and printing it out, all you should need is something like:

class MyClass
  def test(a)
    puts a
  end
end

tmp = MyClass.new
tmp.test("here")

Using a block might function correctly, but you are calling a lot of unnecessary code and making the true nature of your code unclear.

Proper block usage aside, let me address the particular error message you are seeing. When you say tmp.test do |t|, Ruby is expecting tmp.test to yield a single value which it will temporarily call t and pass to the block (think like the block is a function and you are passing it the argument your yield statement as a parameter). In your case, the method test method must not be yield-ing anything, thus the message "(0 for 1)" implies that it is seeing zero objects yielded when it is expecting to see one. I don't know what your code for test does, but check and make sure that test yields exactly one value.

bta
Actually it wasn't my idea to pass a block to a function, that piece of code is something I can't change (it's part of an assignment), and yes, if it is up to me, I would have gone the obvious and simpler route.
Bob