Reputation: 14051
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
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:
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)instance_eval
for the block on the objectBelow 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