Abdo
Abdo

Reputation: 14051

How to achieve this Ruby syntax

I saw the following code yesterday (in the fruity gem)

How can I write something like this? (I'm answering my own question below but feel free to suggest edits or other ways to solve this problem :-) )

Note that "slow", "also_slow" and the other methods called below do not exist:

require 'fruity'
compare do
  slow      { sleep(0.06) }
  also_slow { sleep(0.03); sleep(0.03) }
  quick     { sleep(0.03) }
  quicker   { sleep(0.01) }
end

Upvotes: 0

Views: 67

Answers (1)

Abdo
Abdo

Reputation: 14051

I knew it has to do with method_missing but wanted to write something like it for the purpose of learning.

In order to achieve this, we need two things:

  1. an object with method_missing where we'll be calling the block because we don't want to have a global method_missing handling the methods (think about slow, also_slow, etc, being called on the object)
  2. a method similar to the compare method above that would call instance_eval for the block on the object

Below goes the code:

require 'benchmark'

# the class which instance will be evaluating our missing methods
class BlockEvaluator
  attr_accessor :hashy

  def initialize
    @hashy = {}
  end

  def method_missing(m, *args, &block)
    # collect missing methods' names into hash with the (inner) block of code passed to it
    # i.e. { sleep(0.06} }
    @hashy[m.to_s] = block if block_given?
  end
end

# the method that will be calling the passed block on an instance of BlockEvaluator
def measure_stuff(&block)
  be = BlockEvaluator.new
  be.instance_eval(&block)

  measurements = {}

  # get the length of the longest method name (slow, also_slow, etc) in order to pad accordingly
  maxlen = be.hashy.keys.map(&:length).max

  be.hashy.each do |k,v|
    puts "#{k.rjust(maxlen)}#{Benchmark.measure(&v).to_s.chomp}"
  end

  nil
end

arr = (1..10_000).to_a
# here goes my own
measure_stuff do
  zip { 100.times { arr.zip([nil]) } }
  product { 100.times { arr.product([nil]) } }
end

Upvotes: 1

Related Questions