0

I'm traversing an object graph and want to pass it a block that will run on each node of the structure from a method - let's called visit.

At the top, I'm going to call with a block and I want to delegate the initial call to visit on the root object to visit on other objects. I can unpack the block into a proc locally using &last_parameter_name - but how do I turn the proc back into a block on my delegated call?

Here's a simplified example where I call first(...) and want to delegate the block through to my call to second(...)

def second(&block)   # ... ? ...
  block.call(72)
end

def first(&block)
  puts block.class     # okay - now I have the Proc version
  puts 'pre-doit'
  block.call(42)
  puts 'post-doit'
  second( ... ? ...)   # how do I pass the block through here?
end

first {|x| puts x*x}

Note: I need to have the same conventions on first() and second() here - i.e. they need to take the same things.

Having read and tried the answers, I've come up with a fuller, working example:

class X 
  def visit(&x)
    x.call(50)
  end
end

class Y < X
  def visit(&x)
    x.call(100)
    X.new.visit(&x)
  end
 end

Y.new.visit {|x| puts x*x}
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Dafydd Rees
  • 6,941
  • 3
  • 39
  • 48
  • I know it's only an example, but if you have `puts` in the block, you don't need double the `puts` inside `def second...`. – Sony Santos Apr 01 '11 at 20:27

3 Answers3

7

If I understand you correctly, then as simply as

second &block
Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
3

This explicit passing around of blocks is not always necessary if you use yield.

def first( &block )
  puts block.class     # okay - now I have the Proc version
  puts 'pre-doit'
  yield 42
  puts 'post-doit'
  second( &block ) #the only reason the &block argument is needed. yield 42 can do without.
end

def second #no block argument here, works all the same 
  yield 72
end

first {|x| puts x*x}
steenslag
  • 79,051
  • 16
  • 138
  • 171
  • Another "trick" I learned just now: if you don't explicitly assign a block to a variable using `def first(&block)` syntax above, you can do it later using `block = Proc.new`. With no parameters, `Proc.new` takes a given block, converts it to a `Proc` and returns it. :) – Mladen Jablanović Apr 02 '11 at 04:42
0

Just call second and pass it the block variable (in this case a Proc).

second block
pgmura
  • 708
  • 5
  • 16