Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Yield within enumerable

I'd like to be able to yield within an enumerable block, in order to create some boilerplate benchmarking code.

Basically I'd like to do something this (simplified):

def iterator( enumerable, &block )
  iterations = enumerable.size
  counter = 0
  enumerable.each do |item|
    counter +=1
    puts "Iterating #{counter}/#{iterations}..."
    yield
  end
end

Then I'd like to be able to use this method in order to wrap this boilerplate benchmarking code around a block I would be iterating, so that I could call something like:

# assuming foo is an enumerable collection of objects
iterator foo do
  item.slow_method
  item.mundane_method
  item.save
end

... and when this code executed I would get the following log output:

Iterating 1/1234...
Iterating 2/1234...
Iterating 3/1234...

It seems like this kind of thing must be possible, but I haven't been able to figure out the syntax, nor what such a thing is called (in order to look it up).

The problem is I need to wrap boilerplate both OUTSIDE the enumerable object that is going to iterate, and also INSIDE the iteration block. I can pass an enumerable object in just fine, but I can't seem to call methods on the iterated objects from within the block I pass in.

I hope this explanation makes sense, I'm having a hard time describing it. Please leave comments if you need clarification on anything, I'll try to explain better.

like image 603
Andrew Avatar asked Jul 30 '11 00:07

Andrew


1 Answers

Ruby's yield statement can take arguments. You would want to say

yield item

This passes the "current" item to your "outside" block.

Hope I understood the question correctly.

ADDENDUM

And here is the code to show it in action:

class Item
  def initialize(id)
    @id = id
  end
  def slow_method()
    puts "slow #@id"
  end
  def mundane_method()
    puts "mundane #@id"
  end
  def save()
    puts "save #@id"
  end
end

foo = [Item.new(100), Item.new(200), Item.new(300)]

def iterator(enumerable, &block)
  iterations = enumerable.size
  counter = 0
  enumerable.each do |item|
    counter +=1
    puts "Iterating #{counter}/#{iterations}..."
    yield item
  end
end

iterator foo do |item|
  item.slow_method
  item.mundane_method
  item.save
end
like image 106
Ray Toal Avatar answered Sep 27 '22 22:09

Ray Toal