如何从模块访问类变量?
问题描述:
我想知道我怎么可以访问模块如何从模块访问类变量?
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
,但仍然无法找到一个方法来解决这个问题。
答
这不是最完美的解决方案,但class_eval作品:
module Entity
def foo
self.class.class_eval('@@rules')
end
end
编辑:其实稍微清洁剂可在Ruby中使用class_variable_get
module Entity
def foo
self.class.class_variable_get(:@@rules)
end
end
答
类变量是怪异的,当涉及到继承。除非你确切地知道你在那里搞砸了什么,否则最好避免它们。在这种情况下,您可能认为您没有使用继承,但实际所做的是将Entity
插入到Person
的祖先中。请参阅:
Person.ancestors
# [Person, Entity, Object, Kernel, BasicObject]
的特定行为是棘手的描述,但短期的版本是,基本上@@rules
是Entity
,Person
,和Car
之间共享!看:
Entity.class_variable_set(:@@rules, 'foo')
puts Car.class_variable_get(:@@rules)
# foo
puts Person.class_variable_get(:@@rules)
# foo
你可能不希望这样!
最好在这里使用一个类实例变量,它对于每个类实际是分开的。
module Entity
# create the class instance variable methods when this is included
def self.included klass
klass.singleton_class.send(:attr_reader, :rules)
end
def foo
puts self.class.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
答
除了已经给出的答案之外,我还发现了某些事情。现在
module MyModule
@@my_variable = 5
define_singleton_method(:my_variable) do
@@my_variable
end
end
你就可以访问两种方式类变量: MyModule::my_variable
或MyModule.my_variable
。
这现在就像一个attr_reader。你可以定义第二个单独的分配方法。
答
这不是我的答案,它是@ Max的答案的一个变种,只是没有公开@rules
变量(参见@Quarktum的评论)。
这里的区别在于我使用的是#module_exec
method,它允许实例变量访问(与#module_eval
不同)。
另外,我也定义了包括类的范围之内的.foo
和#foo
方法,使方法是类的方法,而不是模块的方法(与Car.methods false
测试,查看汽车的方法,而没有继承)。
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
好吧,ty!代码的作品,这很好!我希望能得到一个代码更加优雅的答案! – Quarktum