我想知道如何从模块中访问类变量
module Entity
def foo
# puts @@rules
end
end
class Person
include Entity
attr_accessor :id, :name
@@rules = [[:id, :int, :not_null],
[:name, :string, :not_null]]
end
class Car
include Entity
attr_accessor :id, :year
@@rules = [[:id, :string, :not_null],
[:year:, :int, :not_null]]
end
p = Person.new
c = Car.new
p.foo # [[:id, :int, :not_null], [:name, :string, :not_null]]
c.foo # [[:id, :string, :not_null], [:year, :int, :not_null]]
我查看了cattr_accessor
中的mattr_accessor
和ActiveSupport
,但仍无法找到解决此问题的方法。
答案 0 :(得分:12)
Ruby中的类变量在继承方面很奇怪。除非你确切地知道你在那里搞砸了什么,否则最好避免它们。在这种情况下,您可能认为自己没有使用继承,但include
实际上做的是将Entity
插入Person
的祖先。参见:
Person.ancestors
# [Person, Entity, Object, Kernel, BasicObject]
特定行为难以描述,但简短版本基本上@@rules
,Entity
,和 {{1}之间共享Person
}!看:
Car
你可能不想要那个!
最好在这里使用类实例变量,实际上每个类都是独立的。
Entity.class_variable_set(:@@rules, 'foo')
puts Car.class_variable_get(:@@rules)
# foo
puts Person.class_variable_get(:@@rules)
# foo
答案 1 :(得分:1)
这不是最优雅的解决方案,但class_eval有效:
module Entity
def foo
self.class.class_eval('@@rules')
end
end
编辑:实际上稍微清洁可能是使用class_variable_get
module Entity
def foo
self.class.class_variable_get(:@@rules)
end
end
答案 2 :(得分:0)
除了已经给出的答案之外,这里有一些我在某个时候发现的东西。
module MyModule
@@my_variable = 5
define_singleton_method(:my_variable) do
@@my_variable
end
end
现在,您可以通过两种方式访问类变量:
MyModule::my_variable
或MyModule.my_variable
。
这现在就像attr_reader一样。您可以定义第二个单例分配方法。
答案 3 :(得分:0)
这不是我的答案,它是@ Max答案的变体,只是没有暴露@rules
变量(参见@Quarktum的评论)。 / p>
这里的不同之处在于我使用#module_exec
method,它允许实例变量访问(与#module_eval
不同)。
另外,我在include类的范围内定义了.foo
和#foo
方法,因此方法是类方法而不是模块的方法(使用Car.methods false
进行测试,以查看没有继承的Car方法。
module Entity
# create the class instance variable methods when this is included
def self.included klass
klass.module_exec do
@rules ||= []
def self.foo
puts @rules
end
def foo
self.class.foo
end
end
end
end
class Person
include Entity
attr_accessor :id, :name
@rules = [[:id, :int, :not_null],
[:name, :string, :not_null]]
end
class Car
include Entity
attr_accessor :id, :year
@rules = [[:id, :string, :not_null],
[:year, :int, :not_null]]
end