mark mark - 1 month ago 7
Ruby Question

How to wrap a method that yields in Ruby 1.9

I have a method that prints out a numbered list, yielding to a code block to print a prefix.

arr = %w(a b c)

def print_lines(array)
array.each_with_index do |item, index|
prefix = yield index
puts "#{prefix} #{item}"
end
end

print_lines(arr) do |index|
"(#{index})"
end


This produces the following output:

(0) a
(1) b
(2) c


Now I want to wrap
print_lines
in another method and call it.

def print_lines_wrapped(array)
puts 'print_lines_wrapped'
print_lines(array)
end

print_lines_wrapped(arr) do |index|
"(#{index})"
end


However, this gives me a
LocalJumpError


test_yield.rb:5:in `block in print_lines': no block given (yield) (LocalJumpError)
from test_yield.rb:4:in `each'
from test_yield.rb:4:in `each_with_index'
from test_yield.rb:4:in `print_lines'
from test_yield.rb:16:in `print_lines_wrapped'
from test_yield.rb:19:in `<main>'





Why do I get a
LocalJumpError
?

How can I implement
print_lines_wrapped
such that I can call it like this:

print_lines_wrapped(arr) do |index|
"(#{index})"
end


and get the following output:

print_lines_wrapped
(0) a
(1) b
(2) c


?

Answer

Your wrapper method also has to accept a block and pass it to the wrapped method. There is no implicit passing of the block:

def print_lines_wrapped(array, &block)
  puts 'print_lines_wrapped'
  print_lines(array, &block)
end

Example:

def asdf(&block) puts yield(2) end
def qwer(&block)
  puts "I am going to call asdf"
  asdf &block
end

asdf { |x| x * 3 }
6
=> nil
qwer { |x| x * 5 }
I am going to call asdf
10
=> nil

The & operator converts its operand into a block if possible

 qwer &Proc.new { |x| x * 2 }
 I am going to call asdf
 4