Returning from ruby blocks outside of their original scope-Collection of common programming errors

I wanted to make something that looks like this:

def make_wrapped_block(&block)
  puts "take_block:before"
  func = lambda do
    puts "Before calling make_wrapped_block's passed block"
    block.call
    puts "After calling make_wrapped_block's passed block"
  end
  puts "take block:after"
  func
end

def make_block
  make_wrapped_block do
    puts "Before return"
    return :pi
    puts "After return"
  end
end

make_block.call

..where there would be many make_block methods which generate closures with similar initialization and cleanup provided by make_wrapped_block.

Because the block passed to make_wrapped_block in make_block returns, this causes a LocalJumpError:

[ cpm juno ~/tmp/local-jump ] ruby bad.rb
take_block:before
take block:after
Before calling make_wrapped_block's passed block
Before return
bad.rb:15:in `make_block': unexpected return (LocalJumpError)
        from bad.rb:5:in `call'
        from bad.rb:5:in `make_wrapped_block'
        from bad.rb:20:in `call'
        from bad.rb:20

Now, I can get this idea to work with a slightly different syntax:

def make_wrapped_block(block)
  puts "take_block:before"
  func = lambda do
    puts "Before calling make_wrapped_block's passed block"
    block.call
    puts "After calling make_wrapped_block's passed block"
  end
  puts "take block:after"
  func
end

def make_block
  make_wrapped_block(lambda {
    puts "Before return"
    return :pi
    puts "After return"
  })
end

make_block.call

This works because when you return from an anonymous function created with lambda, it exits the anonymous function, while with Proc.new and anonymous blocks it tries to return from the scope it was defined in. You can’t pass them around and return safely.

Is there a safe way to return from passed blocks outside of the scope they were created?
The second way works well enough, but the syntax is a bit uglier than the first version.