Динамический вызов метода в define_method

#ruby #unit-testing #metaprogramming

#ruby #модульное тестирование #метапрограммирование

Вопрос:

Я довольно новичок в ruby, но нахожусь в ситуации, когда у меня много повторяющихся методов. Пытаясь ВЫСУШИТЬ свой код, я придумал что-то вроде следующего:

 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 — есть ли другой способ написать это и достичь моей цели?

Ответ №1:

Да, вы могли бы начать с исходного имени.

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

Обратите внимание, что такого рода метапрограммирование обычно не имеет особого смысла, если у вас нет очень большого количества тривиальных методов.

Ответ №2:

Вы могли бы попытаться уменьшить количество тривиальных методов. Может быть, вы могли бы заменить some_method , some_method2 , some_method3 на generic_method(attribute_desired) where вы бы вызывали generic_method(1) вместо some_method , call generic_method(2) вместо some_method2 и т.д.

Иногда тестирование может рассказать вам кое-что о тестируемом коде. Если тестирование очень скучное, возможно, это означает, что тестируемый код слишком скучный и имеет слишком много дубликатов.

Ответ №3:

И вот еще одно решение:

 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 , и там трассировки стека мельче.

Кстати, %w(foo bar) обозначает слова и производит ['foo', 'bar'] .

 <<-EOS
  blah blah
  blah blah
EOS
  

это просто строка, которая занимает несколько строк (ЗДЕСЬ документ).

class_eval вычисляет строку как скрипт в контексте текущего класса (class Foobar ). __FILE__ И __LINE__ 1 влияют на путь к файлу и номер строки в трассировке стека.