Ruby on rails 在块内定义方法';在Ruby中仍然可以访问全局范围,而不使用块参数?

Ruby on rails 在块内定义方法';在Ruby中仍然可以访问全局范围,而不使用块参数?,ruby-on-rails,unit-testing,metaprogramming,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 instan

我想简化一些测试。具体地说,我想定义一个块断言方法,在这个方法中,在块内部您可以访问一个特殊的助手方法,同时还可以访问测试上下文。大概是这样的:

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| u context |……

有什么想法吗?

您似乎假设
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