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

Я читаю Метапрограммирование 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 ]

3 голосов
/ 24 марта 2012

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

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

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

Ответ 2: (короткий) Module#define_method закрытый метод добавляет метод в таблицу методов экземпляра Class instance (таблица методов содержит методы экземпляра класса). Это не влияет на собственный класс объекта 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.

2 голосов
/ 24 марта 2012

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

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

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

...