Большинство методов экземпляров, используемых в Ruby, являются глобальными методами. Это означает, что они доступны во всех экземплярах класса, в котором они были определены. Напротив, одноэлементный метод реализован на одном объекте.
Существует очевидное противоречие. Ruby хранит методы в классах, и все методы должны быть связаны с классом. Объект, для которого определен одноэлементный метод, не является классом (это экземпляр класса). Если только классы могут хранить методы, как объект может хранить одноэлементный метод? При создании одноэлементного метода Ruby автоматически создает анонимный класс для хранения этого метода. Эти анонимные классы называются метаклассами, также известными как одноэлементные классы или собственные классы. Метод singleton связан с метаклассом, который, в свою очередь, связан с объектом, для которого был определен метод singleton.
Если в одном объекте определены несколько одноэлементных методов, все они хранятся в одном метаклассе.
class Zen
end
z1 = Zen.new
z2 = Zen.new
def z1.say_hello # Notice that the method name is prefixed with the object name
puts "Hello!"
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
В приведенном выше примере метод say_hello был определен в экземпляре z1 класса Zen, но не в экземпляре z2.
В следующем примере показан другой способ определения одноэлементного метода с тем же результатом.
class Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
В вышеприведенном примере класс << z1 меняет текущее значение self на метакласс объекта z1; затем он определяет метод say_hello в метаклассе. </p>
Оба приведенных выше примера служат для иллюстрации работы одноэлементных методов. Однако существует более простой способ определения одноэлементного метода: использование встроенного метода define_singleton_method.
class Zen
end
z1 = Zen.new
z2 = Zen.new
z1.define_singleton_method(:say_hello) { puts "Hello!" }
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
Ранее мы узнали, что классы также являются объектами (экземплярами встроенного класса, называемого Class). Мы также узнали о методах класса. Методы класса - это не более чем одноэлементные методы, связанные с объектом класса.
Еще один пример:
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Все объекты могут иметь метаклассы. Это означает, что у классов также могут быть метаклассы. В приведенном выше примере class << self изменяет self, поэтому оно указывает на метакласс класса Zabuton. Когда метод определен без явного получателя (класс / объект, для которого будет определен метод), он неявно определяется в текущей области, то есть в текущем значении себя. Следовательно, метод stuff определен в метаклассе класса Zabuton. Приведенный выше пример является еще одним способом определения метода класса. </p>
Подробнее на этот пост о Ruby Classes .