Метапрограммирование. Где происходит диспетчеризация метода, когда мы вызываем метод экземпляра, определенный в методе класса?

Я читаю метапрограммирование Ruby и просто хочу кое-что прояснить в следующем перефразированном коде:

class MyClazz
  def self.my_class_method(name)
    define_method(name) {
      # do stuff
    }
  end

  my_class_method :foo
  my_class_method :bar
end

# The code above generates instance methods:

# def foo
#   do stuff
# end

# def bar
#   do stuff
# end

Q1 Мой первый вопрос касается двух вызовов методов в конце файла: my_class_method :foo а также my_class_method :bar, Правильно ли я считаю, что они оба вызываются автоматически при создании экземпляра объекта MyClazz?

Q2 Когда Ruby генерирует эти методы (def foo а также def bar), он поместит их в собственный класс MyClazz, даже если они являются методами экземпляра. Значит ли это, что Ruby при необходимости ищет собственный класс для методов класса и экземпляра?

Я просто хочу прояснить это, прежде чем углубиться в книгу.

2 ответа

Решение

Ответ 1: (короткий) Они вызываются, когда создается экземпляр ruby. MyClass экземпляр (типа Class).

(длинный) Когда интерпретатор Ruby видит определение класса (class MyClazz) он создает экземпляр этого класса и оценивает весь код внутри определения класса.

В твоем случае MyClazz константа, которая содержит ссылку на объект класса Class, И когда Ruby его инициализирует, он выполняет код внутри определения класса - определяет метод singleton my_class_method этого Class экземпляр и выполняет метод my_class_method дважды в контексте этого Class пример.

Ответ 2: (короткий) Module#define_method закрытый метод добавляет метод в таблицу методов Class экземпляр (таблица методов содержит методы экземпляра класса). Это не влияет на собственный класс объекта istance / объекта класса.

(long) Когда вы вызываете метод экземпляра для объекта, Ruby сначала ищет этот метод в собственном классе этого объекта, затем в суперклассе собственного класса (это будет Class объект класса объекта). Но это не будет выглядеть в собственном классе MyClazzобъект.

Пример:

obj = MyClazz.new
obj.foo # => ok

obj.foo буду искать foo определение метода в собственном классе obj объект, то будет искать методы экземпляра MyClass (экземпляр класса Class), то в суперклассе MyClass объект (в вашем случае это Object класс) и т. д.

obj = MyClass.new
MyClass.my_class_method :baz
obj.baz # => ok

MyClass.my_class_method буду искать my_class_method определение метода в собственном классе MyClass объект (sidenote: собственный класс класса иногда называют метаклассом), и он найдет его здесь и добавит baz метод экземпляра для класса MyClass,

A1: Да, эти методы создаются при создании экземпляра.

A2: Расс Олсен отлично объясняет это в своей книге Eloquent Ruby. Собственный класс (или одноэлементный класс) "находится между каждым объектом и его обычным классом". Таким образом, когда Ruby не находит метод, который ищет в методах экземпляра, он начинает перемещаться по дереву наследования. Следующая остановка - собственный класс, а оттуда - сам класс.

Олсен также дает интересную дискуссию о том, что все методы класса на самом деле являются одноэлементными методами между новым классом и объектом класса.

Другие вопросы по тегам