Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping a block in method calls that accept blocks by name

Tags:

ruby

block

I have a number of methods that I call like this:

with_this do
  with_that do
    and_in_this_context do
      yield
    end
  end
end

I remember there was a trick to recursively wrap such a block call. How do I write a method that does block wrapping for me?

def in_nested_contexts(&blk)
  contexts = [:with_this, :with_that, :and_in_this_context]
  # ... magic probably involving inject
end
like image 667
Julik Avatar asked Oct 21 '22 13:10

Julik


1 Answers

You can indeed use inject to created nested lambdas or procs, which you can call at the end. You need your given block to be the interior of the nest, so you reverse your array and use that block as the initial value, then wrap each successive function around the result from inject:

def in_nested_contexts(&blk)
  [:with_this, :with_that, :and_in_this_context].reverse.inject(blk) {|block, symbol|
    ->{ send symbol, &block }
  }.call
end

If you wrap your with_this, et al methods with before and after puts statements, you can see this in action:

in_nested_contexts { puts "hello, world" }
#=> 
  with_this start
  with_that start
  context start
  hello, world
  context end
  with_that end
  with_this end
like image 138
Zach Kemp Avatar answered Oct 28 '22 23:10

Zach Kemp