tags:

views:

73

answers:

2

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?

+6  A: 

It seems to me that this is best done using recursion

Here is the code:

def using_resources(*res, &block)

   first_resource = res.shift

   if res.length > 0 
     first_resource.run do
      using_resources(*res, &block)
     end
   else
     first_resource.run do
       block.call
     end
   end

end

And use it like so:

using_resources Resource.new('/tmp'), Resource.new('http://stackoverflow.com') do
  do_some_processing
end

You do say, "which takes an array of resources." If you have an Array already and need to use it, you can either splat the Array outside the call:

 using_resources *my_array do
   do_some_processing
 end

Or inside the method definition, which allows you to call it either with an Array or a list of Resources:

def using_resources(*res, &block)
  res = [*res]
  # rest as above
end
Senad Uka
+3  A: 

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 ...

rampion