如何实现这种Ruby语法

时间:2014-02-06 14:46:08

标签: ruby

我昨天看到了以下代码(在fruity gem中)

我怎么写这样的东西? (我在下面回答我自己的问题,但随时可以建议编辑或其他方法来解决这个问题:-))

请注意,“slow”,“also_slow”以及下面调用的其他方法不存在:

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

1 个答案:

答案 0 :(得分:1)

我知道这与method_missing有关,但是为了学习的目的,我想写一些类似的东西。

为了实现这一目标,我们需要两件事:

  1. 一个method_missing的对象,我们将调用该块,因为我们不希望有一个全局method_missing处理方法(想想slow,also_slow等,在对象)
  2. 类似于上面的比较方法的方法,它会为对象上的块调用instance_eval
  3. 下面是代码:

    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