Imagine i have some resource objects with a run method, which executes the block parameter under the lock held for that resource. For example, like this:
r = Resource("/tmp/foo")
r.run { ... }
How can I write a ruby method which takes an array of resources and executes its block parameter under the lock held for all resources, like:
def using_resources(*res, &block)
r[0].run do; r[1].run do; r[2].run do ...
yield;
end; end; end; ...
end
Is it possible at all?
The &block is a way of sending a piece of Ruby code in to a method and then evaluating that code in the scope of that method.
In Ruby, methods can take blocks implicitly and explicitly. Implicit block passing works by calling the yield keyword in a method. The yield keyword is special. It finds and calls a passed block, so you don't have to add the block to the list of arguments the method accepts.
Blocks are syntactic structures in Ruby; they are not objects, and cannot be manipulated as objects. It is possible, however, to create an object that represents a block. Depending on how the object is created, it is called a proc or a lambda.
The return keyword always returns from the method or lambda in the current context. In blocks, it will return from the method in which the closure was defined. It cannot be made to return from the calling method or lambda.
You could also do this using #inject
:
def using_resources(*resources, &block)
(resources.inject(block){ |inner,resource| proc { resource.run(&inner) } })[]
end
As you step through the array, you wrap each resource's invocation of the previous Proc in a new Proc, and then pass that to the next resource. This gets the locks in reverse order (the last resource given is the first one unlocked), but that could changed by using resources.reverse.inject ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With