我正在寻找一种通过继承自动初始化类变量的解决方案(使其可用作访问器并将其初始化为某个值)。但是我不想继承这个值,只是每次在每个类上开始一个新的新对象。
我一直在看class_attributes
,并认为我找到了一个解决方法,但它似乎没有像我想的那样工作(即使它工作,它很可能不会做我想要的东西,因为相同的阵列将在任何地方使用所以它的行为就像一个@@变量)
class AbstractClass
class_attribute :metadata
@metadata = [] # initialize metadata to an empty array
def self.add_metadata(metadata)
@metadata << metadata
end
end
def ChildClass < AbstractClass
add_metadata(:child_class1)
end
def ChildClass2 < AbstractClass
add_metadata(:child_class2)
end
我想要以下内容:
AbstractClass.metadata # Don't really care about this one
ChildClass1.metadata # => [:child_class1]
ChildClass2.metadata # => [:child_class2]
我可以想一个使用AS :: Support模块的方法
module InitializeClassInstanceVars
extend ActiveSupport::Concern
included do
class_attribute :metadata
self.metadata = []
end
end
...并在每个嵌套类中包含此模块(我相信这是mongoid实际上的例子)
但我希望我能通过继承直接做到这一点
在继承类变量时,您不必初始化它。 Ruby样式是在尚未设置变量并且第一次访问变量时返回并指定默认值。
只需为此创建另一个类方法:
class AbstractClass
def self.metadata
@metadata ||= []
end
def self.add_metadata(metadata)
self.metadata << metadata
end
end
class ChildClass1 < AbstractClass
add_metadata(:child_class1)
end
class ChildClass2 < AbstractClass
add_metadata(:child_class2)
end
AbstractClass.metadata # => []
ChildClass1.metadata # => [:child_class1]
ChildClass2.metadata # => [:child_class2]
钩子是一个好主意,你只是在错误的一个:)如果你想在每次继承你的类时运行代码,那么inherited
是使用的:
class AbstractClass
class << self
attr_accessor :metadata
def inherited(child)
child.instance_variable_set(:@metadata, [child.name])
end
end
end
class ChildClass1 < AbstractClass; end
class ChildClass2 < AbstractClass; end
ChildClass1.metadata
# => ["ChildClass1"]
ChildClass2.metadata
# => ["ChildClass2"]
鉴于问题被标记为rails,您还应该有String#underscore
;用child.name
取代child.name.underscore.to_s
得到[:child_class1]
。
编辑:我可能误解了这个问题。如果你只想从一个可以添加的空数组开始,chumakoff的答案就更简单了。