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в собственном Fooклассе, доступный с помощью обычного синтаксиса вызова метода: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)
Надеюсь это поможет.