2015-05-04 104 views
5

我想知道我怎么可以访问模块如何从模块访问类变量?

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,但仍然无法找到一个方法来解决这个问题。

回答

1

这不是最完美的解决方案,但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 
+0

好吧,ty!代码的作品,这很好!我希望能得到一个代码更加优雅的答案! – Quarktum

12

类变量是怪异的,当涉及到继承。除非你确切地知道你在那里搞砸了什么,否则最好避免它们。在这种情况下,您可能认为您没有使用继承,但实际所做的是将Entity插入到Person的祖先中。请参阅:

Person.ancestors 
# [Person, Entity, Object, Kernel, BasicObject] 

的特定行为是棘手的描述,但短期的版本是,基本上@@rulesEntityPersonCar之间共享!看:

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 
+0

我喜欢这个答案,但是在这种情况下,属性'rules'正在被暴露 – Quarktum

+0

您可以轻松地将它变成读者而不是访问者,我会编辑我的答案。 – Max

+0

它仍然被暴露(无论如何,使用反射作为第一个答案,它也可以访问) – Quarktum

0

除了已经给出的答案之外,我还发现了某些事情。现在

module MyModule 
    @@my_variable = 5 
    define_singleton_method(:my_variable) do 
    @@my_variable 
    end 
end 

你就可以访问两种方式类变量: MyModule::my_variableMyModule.my_variable

这现在就像一个attr_reader。你可以定义第二个单独的分配方法。

0

这不是我的答案,它是@ 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