动态方法调用define_method

时间:2011-10-04 17:48:17

标签: ruby unit-testing metaprogramming

我对红宝石很新,但是在我有许多重复方法的情况下。在尝试干掉我的代码时,我提出了类似以下的内容:

class Foobar
  def some_method
    #
  end

  def some_method2
    #
  end

  def some_calculation
    #
  end

  [:some_method_test, :some_method2_test].each do |method|
    define_method method do
      return self.send(method.to_s.chomp "_test") / some_calculation
    end
  end
end

我的问题是关于.to_s.comp--还有另一种方式来写这个并实现我的目标吗?

3 个答案:

答案 0 :(得分:2)

是的,您可以从原始名称开始。

[:some_method, :some_method2].each do |method|
  define_method :"#{method}_test" do
    return self.send(method) / some_calculation
  end
end

请注意,除非您拥有大量无关紧要的方法,否则这种元编程通常没有多大意义。

答案 1 :(得分:2)

您可以尝试减少无关紧要的方法。也许您可以将some_methodsome_method2some_method3替换为generic_method(attribute_desired),而不是generic_method(1),而是some_method,请致电generic_method(2)而不是some_method2等等。

有时候测试可以告诉你一些正在测试的代码。如果测试非常无聊,也许这意味着被测试的代码太无聊并且有太多重复。

答案 2 :(得分:1)

以下是另一种解决方案:

class Foobar
  # Non-test method definitions ...

  %w(some_method some_method2).each do |mthd|
    class_eval(<<-EOS, __FILE__, __LINE__ + 1)
      def #{mthd}_test
        #{mthd} / some_calculation
      end
    EOS
  end
end

通过这种方式,方法定义本身有点慢,但它们运行得更快,因为它们没有像send那样调用反射方法,并且堆栈跟踪较浅。

BTW,%w(foo bar)代表,并产生['foo', 'bar']

<<-EOS
  blah blah
  blah blah
EOS

只是一个传播多行的字符串(HERE doc)。

class_eval在当前类(类Foobar)的上下文中将字符串计算为脚本。 __FILE____LINE__ + 1会影响堆栈跟踪中的文件路径和行号。