Метаклассы (eigenclasses, singleton classes) — это специальные скрытые классы, которые Ruby создает для каждого объекта. Они лежат в основе системы объектов Ruby и позволяют реализовать многие мощные возможности языка.
Метакласс — это:
obj = Object.new
# Получаем метакласс
metaclass = class << obj; self; end
Когда вы добавляете метод к конкретному объекту, он помещается в его метакласс:
def obj.special_method
"I'm special!"
end
# Метод хранится в метаклассе
metaclass.instance_methods(false) # => [:special_method]
hero = "Alice"
class << hero
def greet
"Hello, I'm #{self}!"
end
end
hero.greet # => "Hello, I'm Alice!"
"Bob".greet # => NoMethodError
Когда вы определяете методы класса, вы на самом деле работаете с метаклассом:
class Person
def self.species
"Homo sapiens"
end
# Эквивалентно:
class << self
def lifespan
80
end
end
end
Person.species # => "Homo sapiens"
Person.lifespan # => 80
Метаклассы образуют свою цепочку наследования:
class A; end
class B < A; end
# Цепочка метаклассов:
# B -> A -> Object -> BasicObject
Когда Ruby ищет метод:
obj = Object.new
eigenclass = class << obj; self; end
eigenclass.class # => Class
obj.class # => Object
eigenclass.superclass # => Object
class Module
def redefine_method(name, &block)
eigenclass = class << self; self; end
eigenclass.define_method(name, &block)
end
end
class Person; end
Person.redefine_method(:inspect) { "Custom inspect" }
Person.inspect # => "Custom inspect"
module M
def module_method; end
end
class C
include M
end
obj = C.new
class << obj
include M
end
# Методы модуля M будут в разных местах цепочки
Производительность:
Читаемость:
Безопасность:
Метаклассы в Ruby:
Ключевые моменты:
class << obj; ... end
— синтаксис для работы с метаклассомИспользуйте метаклассы для:
Помните о балансе между мощью и сложностью — не все задачи требуют работы с метаклассами напрямую.