class << self- це більше, ніж просто спосіб оголошення методів класу (хоча його можна використовувати і таким чином). Можливо, ви бачили таке вживання, як:
class Foo
class << self
def a
print "I could also have been defined as def Foo.a."
end
end
end
Це працює, і це еквівалентно def Foo.a, але те, як це працює, є делікатним. Секрет полягає в тому self, що в цьому контексті посилається на об'єкт Foo, клас якого є унікальним, анонімним підкласом Class. Цей підклас називається Foo«s eigenclass . Таким чином , def aстворюється новий метод , званий aв Fooeigenclass «S, доступний за нормальним синтаксису виклику методу: Foo.a.
А тепер давайте розглянемо інший приклад:
str = "abc"
other_str = "def"
class << str
def frob
return self + "d"
end
end
print str.frob
print other_str.frob
Цей приклад такий самий, як і останній, хоча спочатку це важко сказати. frobвизначається не для Stringкласу, а для власного класу strунікального анонімного підкласу String. Так само strмає frobметод, але екземпляри Stringзагалом - ні. Ми могли б також замінити методи String (дуже корисні в певних хитрих сценаріях тестування).
Тепер ми готові зрозуміти ваш оригінальний приклад. Усередині Fooініціалізації метод «и, selfвідноситься не до класу Foo, але в якийсь - то конкретної інстанції в Foo. Його власний клас є підкласом Foo, але це не так Foo; цього не могло бути, інакше фокус, який ми побачили у другому прикладі, не міг спрацювати. Отже, щоб продовжити приклад:
f1 = Foo.new(:weasels)
f2 = Foo.new(:monkeys)
f1.weasels = 4
f2.monkeys = 5
print(f1.monkeys)
Сподіваюся, це допомагає.