如何从模块访问类变量?

Qua*_*tum 6 ruby

我想知道如何从模块中访问类变量

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]]
Run Code Online (Sandbox Code Playgroud)

我看了看cattr_accessor,并mattr_accessorActiveSupport,但仍无法找到一个方法来解决这个问题.

Max*_*Max 12

Ruby中的类变量在继承方面很奇怪.除非你确切地知道你在那里弄乱了什么,否则最好避免它们.在这种情况下,您可能认为您没有使用继承,但include实际上做的是插入Entity到祖先的中Person.看到:

Person.ancestors
# [Person, Entity, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)

具体的行为是棘手的描述,但短期的版本是,基本上@@rules之间共享Entity,Person, Car!看:

Entity.class_variable_set(:@@rules, 'foo')
puts Car.class_variable_get(:@@rules)
# foo
puts Person.class_variable_get(:@@rules)
# foo
Run Code Online (Sandbox Code Playgroud)

你可能不想那样!

最好在这里使用一个类实例变量,实际上每个类都是独立的.

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
Run Code Online (Sandbox Code Playgroud)


Cha*_*lie 2

这不是最优雅的解决方案,但class_eval有效:

module Entity
  def foo
    self.class.class_eval('@@rules')
  end
end
Run Code Online (Sandbox Code Playgroud)

编辑:实际上稍微干净一点可能是使用class_variable_get

module Entity
  def foo
    self.class.class_variable_get(:@@rules)
  end
end
Run Code Online (Sandbox Code Playgroud)