Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

It's common pattern when you need to assign a variable inside a block

def query(sql)
  logger.debug "Db: Executing query #{sql}"
  result = nil
  ts = Benchmark.realtime do
    result = @db.exec sql
  end
  logger.debug "Db: Query completed in #{ts}"
  result
end

Is there a more elegant way to rewrite this snippet?

share|improve this question

1 Answer 1

I am afraid your code cannot be simplified further due to the imperative nature of Benchmark.realtime (it would have been better if it also returned the result of the block). Anyway, I think the best solution is to abstract it and write a wrapper method. For example:

def benchmark(msg)
  logger.debug(msg)
  result = nil
  ts = Benchmark.realtime(&block) { result = yield }
  logger.debug("Completed in #{ts} seconds")
  result
end

def query(sql)
  benchmark("DB: Executing query #{sql}") do
    @db.exec(sql)
  end
end

Now, if your question was on a more generic plane, let's say, that you have lots of methods that work like realtime which force you write a lot of boilerplate, I'd propose this generic Object#capture wrapper:

class Object
  def capture(method, *args)
    result2 = nil
    result1 = send(method, *args) { |*bargs| result2 = yield(*bargs) }
    [result1, result2]
  end
end

realtime_output, block_output = Benchmark.capture(:realtime) do
  "my output"
end #=> [7.263e-06, "my output"]
share|improve this answer
    
Yeah, I was asking about the generic pattern, the Benchmark.realtime is of course wrapped –  synapse Oct 12 '12 at 13:39
    
@synapse: I updated the answer, see the second snippet. –  tokland Oct 17 '12 at 14:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.