Синглтон-методы Ruby с (class_eval, define_method) vs (instance_eval, define_method) - PullRequest
17 голосов
/ 03 июля 2010

Метапрограммирование в ruby ​​великолепно, потому что я постоянно использую его для эмуляции программирования на основе прототипов и быстрого написания прототипных решений для некоторых задач, чтобы проверить их жизнеспособность.Поэтому я хотел бы знать, есть ли существенная разница между следующими частями кода:

(class << some_object; self; end).class_eval do
  define_method(:method_name) do ... method body ... end
end

и

(class << some_object; self; end).instance_eval do
  define_method(:method_name) do ... method body ... end
end

Обе версии кода определяют одноэлементный метод, и я имею в видупока не сталкиваюсь с тем, что заставило меня выбрать комбинацию (instance_eval, define_method) вместо комбинации (class_eval, define_method) для определения одноэлементного метода, и мне интересно, есть ли существенное различие между ними.

1 Ответ

21 голосов
/ 03 июля 2010

Нет разницы для define_method.Но есть разница, когда вы используете def.

o = Object.new  

# class_eval example
class << o; self; end.class_eval { def test1;  :test1; end  }
o.test1 #=> test1

# instance_eval example
class << o; self; end.instance_eval { def test2; :test2; end }
o.test2 #=> NoMethodError

Почему разница в поведении между def и define_method?define_method является вызовом метода и поэтому работает с self в контексте eval.self в instance_eval и class_eval одинаковы - это получатель (собственный класс o).

Однако def ведет себя по-другому, он работает не на self, а на default definee.В случае class_eval значение default definee совпадает с self, но для instance_eval это метакласс self.

Как получить доступ к методу test2, определенному выше?test2 должен быть методом экземпляра, определенным в метаклассе собственного класса o.

Это метод класса на собственном классе o:

class << o; test2; end #=> :test2
...