Ruby - 自动初始化子classes的class个实例变量而不继承值
Ruby - automatically initialize class instance variables of child classes without inheriting the value
我正在寻找一种通过继承自动初始化 class 变量的解决方案(使其可用作访问器并将其初始化为某个值)。但我不想继承该值,每次 class 上每次都从一个新对象开始。
我一直在查看 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
...并将此模块包含在每个嵌套的 class 中(例如,我相信这就是 mongoid 实际执行的操作)
但我希望我可以通过继承直接做到这一点
您不必在 class 变量被继承时对其进行初始化。 Ruby 风格是return 并在变量未设置且第一次访问时赋默认值。
只需为此创建另一个 class 方法:
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]
Hooks 是个好主意,你只是用错了 :) 如果你想 运行 每次 inherits 你的 class,那么 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 的答案更简单。
我正在寻找一种通过继承自动初始化 class 变量的解决方案(使其可用作访问器并将其初始化为某个值)。但我不想继承该值,每次 class 上每次都从一个新对象开始。
我一直在查看 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
...并将此模块包含在每个嵌套的 class 中(例如,我相信这就是 mongoid 实际执行的操作)
但我希望我可以通过继承直接做到这一点
您不必在 class 变量被继承时对其进行初始化。 Ruby 风格是return 并在变量未设置且第一次访问时赋默认值。
只需为此创建另一个 class 方法:
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]
Hooks 是个好主意,你只是用错了 :) 如果你想 运行 每次 inherits 你的 class,那么 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 的答案更简单。