Наследовать переменные экземпляра уровня класса в Ruby?
Я хочу, чтобы дочерний класс унаследовал переменную экземпляра уровня класса от своего родителя, но я не могу понять это. В основном я ищу такую функциональность:
class Alpha
class_instance_inheritable_accessor :foo #
@foo = [1, 2, 3]
end
class Beta < Alpha
@foo << 4
def self.bar
@foo
end
end
class Delta < Alpha
@foo << 5
def self.bar
@foo
end
end
class Gamma < Beta
@foo << 'a'
def self.bar
@foo
end
end
и затем я хочу, чтобы это выход такой:
> Alpha.bar
# [1, 2, 3]
> Beta.bar
# [1, 2, 3, 4]
> Delta.bar
# [1, 2, 3, 5]
> Gamma.bar
# [1, 2, 3, 4, 'a']
очевидно, этот код не работает. В основном я хочу определить значение по умолчанию для переменных экземпляра уровня класса в родительском классе, которые наследуют его подклассы. Изменение подкласса будет значением по умолчанию для подкласс. Я хочу, чтобы все это произошло без изменения значения одного класса, влияющего на его родителя или братьев и сестер. Class_inheritable_accessor дает именно поведение я хочу... но для переменной класса.
Я чувствую, что, возможно, прошу слишком много. Есть идеи?
3 ответов
используйте mixin:
module ClassLevelInheritableAttributes
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def inheritable_attributes(*args)
@inheritable_attributes ||= [:inheritable_attributes]
@inheritable_attributes += args
args.each do |arg|
class_eval %(
class << self; attr_accessor :#{arg} end
)
end
@inheritable_attributes
end
def inherited(subclass)
@inheritable_attributes.each do |inheritable_attribute|
instance_var = "@#{inheritable_attribute}"
subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
end
end
end
end
включение этого модуля в класс дает ему два метода класса: inheritable_attributes и inherited.
Унаследованный метод класса работает так же, как самого себя.включенный метод в показанном модуле. Всякий раз, когда класс, включающий этот модуль, получает подкласс, он устанавливает переменную экземпляра уровня класса для каждой из объявленных переменных экземпляра наследования уровня класса (@inheritable_attributes).
рельсы это в рамках как метод называется class_attribute. Вы всегда можете проверить источник для данного метода и сделайте свою собственную версию или скопируйте ее дословно. Единственное, что нужно остерегаться, это то, что вы не меняйте изменяемые элементы на месте.
то, что я сделал в своем проекте для использования resque, - это определить базу
class ResqueBase
def self.inherited base
base.instance_variable_set(:@queue, :queuename)
end
end
в других дочерних заданиях экземпляр очереди будет установлен по умолчанию. Надеюсь, это поможет.