Подождите… что?
Не знаю, как вы, но это была моя точная реакция, когда я впервые услышал выступление Nadia Odunayo
в RubyConf KL 2018
(заметьте, один из самых увлекательных выступлений, которые я когда-либо слышал!), В котором она показала, что Руби не имеет методов класса.
Когда я только начал изучать Ruby, мне сказали, что в Ruby есть два типа методов:
- Методы класса
- Методы экземпляра
Что ж, поначалу в этом есть большой смысл -
Класс - это объект, и когда вы вызываете
.new
для класса, вы создаете новый экземпляр этого объекта.
Следовательно, методы экземпляра доступны только в экземплярах этого класса.
Хорошо, тогда ... о чем я говорю, когда сказал, что в Ruby нет методов класса?
Родители. Бабушка и дедушка. Предки..!
Первое, что нам нужно понять, это что-то, что в Ruby называется Ancestor Chains.
Ancestors Chains жизненно важен для понимания того, как работает Ruby; вся цепочка вызовов методов работает из-за цепочки, но здесь я попытаюсь дать слишком упрощенное объяснение.
В Ruby все наследует Object
, а каждое Object
наследует от BasicObject
.
Давай быстро проверим!
Когда вы вызываете метод, он вызывает метод текущего класса; если текущий класс не имеет этого метода, он идет вверх по цепочке предков, пока не найдет его.
Еще не ясно? Я получил! Странная метафора
Представьте, что вы всего лишь ребенок, и этот надоедливый Маленький Джонни, который пытается перехитрить вас, робко спрашивает: «Вы знаете, что
.planets
есть в нашей солнечной системе? Готов поспорить, что нет! ».
Ну, на самом деле ты не знаешь ответа, но ты не позволил Маленькому Джонни одержать победу, поэтому ставишь цель своей жизни узнать это и спрашиваешь родителей: «Какие
.planets
в нашем? Солнечная система?". И что ж, ваши родители этого тоже не знают, поэтому они продолжают спрашивать своих родителей, которые случайно знают ответ.
Теперь ваша очередь смущенно ухмыльнуться в ответ Маленькому Джонни и сказать ему, какой будет ответ.
Итак, теперь, когда кто-то спрашивает вас, какие
.planets
в нашей солнечной системе, у вас есть ответ от ваших бабушек и дедушек.
Насколько это актуально? Итак, мы говорили о том, как работает поиск методов, и в моем последнем посте я говорил о повторном использовании методов (Module
) с include
, extend
и prepend
. Теперь давайте посмотрим на их соответствующие цепочки предков, когда вы include
, extend
и prepend
модуль.
Вы поймете нечто странное:
- Когда вы
include
, модуль вставляется после текущего класса, а это значит, что это будет первое, на что вы попадете, когда не сможете найти метод в текущем классе. prepend
является противоположностьюinclude
; он вставляет перед, поэтому технически вы все равно не сможете его вызвать.- Вы не видите модуль в цепочке предков при расширении модуля
Погодите, мы точно знаем, что когда мы extend
модуль, мы получаем доступ к методам класса, и мы также знаем, что вызов метода происходит через цепочки предков, но ... как extend
может работать, если модуль не входит в цепочку предков?
Причина в том, что в Ruby есть что-то под названием Singleton Class (иногда называемое Metaclass
, Anonymous Class
или Eigenclass
)
Каждый раз, когда вы инициализируете класс в Ruby, создаются два объекта - Foo
и Foo’s Singleton Class
. Чтобы доказать это, в своем выступлении Надя показала отличный способ проверить текущее количество классов с помощью ObjectSpace
. ObjectSpace
- это, по сути, способ взаимодействия со всеми текущими объектами Ruby в памяти.
Давайте посмотрим, какой .class
класс вы только что создали.
Как вы могли заметить ранее, существует альтернативный способ инициализации класса, как показано ниже:
Выглядит очень знакомо, не так ли? Foo - это экземпляр класса.
Почему это важно? Потому что это означает, что обычные методы класса, которые, как вы привыкли думать, выполняются на Foo
, на самом деле являются методом экземпляра на Class
. - Это работает, потому что Foo
является экземпляром Class
!
Теперь мы знаем, что классы-одиночки не видны в цепочках предков. Помните, чего еще не было видно в цепочке? Модуль, когда вы делаете extend
!
Мы можем проверить цепочку предков самого одноэлементного класса.
Мы также можем доказать, что то, что мы узнали как class_method
, на самом деле является просто методом экземпляра в одноэлементном классе.
Итак, теперь мы знаем, что extend
фактически делает за кулисами, по сути, include
в самом синглтон-классе. Докажем!
Все еще работает!
Но да, написание полной формы требует ошеломляющих трех дополнительных слов, это много работы, поэтому вместо этого у нас есть extend
, чтобы избавить нас от этого нажатия клавиши!
Примечание автора
Я напишу еще несколько статей, а пока проверю свой последний пост на хуках included
, extended
и prepended
!
Уф, это для моего второго сообщения в блоге. С нетерпением жду возможности узнать больше и поделиться!
Первоначально опубликовано на Dev.to