在块的范围内定义方法,同时仍然可以访问Ruby中的全局范围,而不使用块参数?

时间:2011-03-21 17:44:31

标签: ruby-on-rails unit-testing metaprogramming

我想简化一些测试。具体来说,我想定义一个块断言方法,在块中你可以访问一个特殊的辅助方法,同时还可以访问测试上下文。像这样:

def assert_metric(report, metric, &block)
  def sum(value, *filters)
    filters.each do |filter|
      assert_equal value, report.sum(metric, filter)
    end
  end
  instance_eval(&block)
end

assert_metric report, :select_count do
  sum 1
  sum 1, :bookmark, :like
  sum 0, :vote
end

这样做的正确方法是什么?

约束*:

  • sum方法在当前正在执行的测试的上下文中执行(因此您可以执行assert_equal并访问所有实例变量。
  • sum在该区块之外无法使用
  • 您不会产生阻止参数(即do |test_context|...

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您似乎假设def sum的工作方式类似于Python中的嵌套函数。它没有。这将在您的测试类中定义一个方法。没有办法仅在另一个方法中定义方法 - 方法属于类或对象。但是,您可以定义仅存在实现该方法的对象。

如果我正确理解您的要求,最接近的等价物将是:

require 'delegate'

def assert_metric(report, metric, &block)
  ctx = SimpleDelegator.new(self)
  ctx.singleton_class.class_eval do
    define_method(:sum) do
      filters.each {|filter| assert_equal value, report.sum(metric, filter)}
    end
  end
  ctx.instance_eval(&block)
end