You can't directly wrap a thread around each statement in the block body, if they can be arbitrary statements; there's no way to get that sort of control over the execution of a block body in Ruby. If you can restrict what goes in the block body, you have some more flexibility.
If each of the statements you are executing is simply a method call, as you imply in your example, you can use instance_exec
to execute that block on a proxy object, which uses method_missing
to spawn a new thread and then forward the method call on to the real object (or do whatever wrapper you're interested in; for the sake of example, I'll just wrap with some print statements):
class Proxy
def initialize obj
@obj = obj
end
def method_missing method, *args
puts "<wrapper>"
@obj.send method, *args
puts "</wrapper>"
end
end
class MethodWrapper
def tell_me_a_joke
puts "Knock, knock?"
end
def whos_there
puts "Orange"
end
def orange_who
puts "Orange you glad I didnt say banana?"
end
def wrap_around &blk
Proxy.new(self).instance_exec &blk
end
end
And here's how you can use it:
>> MethodWrapper.new.wrap_around { tell_me_a_joke; whos_there; orange_who }
<wrapper>
Knock, knock?
</wrapper>
<wrapper>
Orange
</wrapper>
<wrapper>
Orange you glad I didnt say banana?
</wrapper>
=> nil
The previous follows the pattern that you gave in your question, but it's less than ideal as only methods that are forwarded to the underlying object get wrapped:
>> MethodWrapper.new.wrap_around { tell_me_a_joke; puts "something" }
<wrapper>
Knock, knock?
</wrapper>
something
=> nil
You could instead just use instance_exec
directly, and call the a wrapper method that takes a block, to get almost the same effect, though slightly less DRY as you need to call your wrapper method each time:
class SimpleWrapper
def tell_me_a_joke
puts "Knock, knock?"
end
def whos_there
puts "Interrupting cow"
end
def interrupting_co
puts "Moooooo!"
end
def wrap
puts "<wrap>"
yield
puts "</wrap>"
end
end
And in use:
>> SimpleWrapper.new.instance_exec do
wrap { tell_me_a_joke }
wrap { whos_there }
wrap { interrupting_co }
wrap { puts "Something" }
end
<wrap>
Knock, knock?
</wrap>
<wrap>
Interrupting cow
</wrap>
<wrap>
Moooooo!
</wrap>
<wrap>
Something
</wrap>
=> nil