Краткий ответ: переменные экземпляра не наследуются подклассами
Более длинный ответ: проблема в том, что вы написали @bar = []
в теле класса (вне любого метода). Когда вы устанавливаете переменную экземпляра, она сохраняется на том, что в данный момент self
. Когда вы находитесь в теле класса, self
является объектом класса Foo. Итак, в вашем примере @foo
определяется для объекта класса Foo.
Позже, когда вы пытаетесь найти переменную экземпляра, Ruby ищет то, что в данный момент self
. Когда вы вызываете add_bar из Baz, self
это Baz. Также self
это STILL Baz в теле add_bar (хотя этот метод в Foo). Итак, Ruby ищет @bar
в Baz и не может его найти (потому что вы определили его в Foo).
Вот пример, который может прояснить ситуацию
class Foo
@bar = "I'm defined on the class object Foo. self is #{self}"
def self.get_bar
puts "In the class method. self is #{self}"
@bar
end
def get_bar
puts "In the instance method. self is #{self} (can't see @bar!)"
@bar
end
end
>> Foo.get_bar
In the class method. self is Foo
=> "I'm defined on the class object Foo. self is Foo"
>> Foo.new.get_bar
In the instance method. self is #<Foo:0x1056eaea0> (can't see @bar!)
=> nil
Это, по общему признанию, немного сбивает с толку и является общим камнем преткновения для людей, плохо знакомых с Ruby, так что не расстраивайтесь. Эта концепция наконец-то возникла у меня, когда я прочитал главу «Метапрограммирование» в Программирование на Ruby (он же «Кирка»).
Как бы я решил вашу проблему: Посмотрите на метод Rails class_attribute
. Он учитывает то, что вы пытаетесь сделать (определение атрибута родительского класса, который может наследоваться (и переопределяться) в его подклассах).