2015-05-04 106 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