使用Class.new创建的类中的常量

时间:2012-04-30 15:23:27

标签: ruby metaprogramming

我在Ruby(1.9.3)中编写了一小段代码,我使用了一对简单的“类似enum”的类,用 const_set 定义一些常量和一些行为这些常数(例如,类可能有常量 MON TUE ...和天数:: MON.succ < / strong>应评估为 TUE )。

我对这些课程非常满意。然而,在增加我的代码时,我有时需要添加更多代码,而且我不喜欢有五个或更多类共享99%源代码的想法,例如:

class Days
  NAMES = %w( MON TUE ... )
  INSTANCES = []

  def initialize(num)
    @num = num
  end

  # An example operation
  def +(n)
    INSTANCES[(@num + n) % INSTANCES.length]
  end

  # Another example operation
  def succ
    self + 1
  end

  def to_s
    NAMES[@num]
  end

  NAMES.each_with_index do |name, idx|
    instance = new(idx)
    INSTANCES[idx] = instance
    const_set name, instance
  end
end

class Months
  NAMES = %w( JAN FEB ... )
  ...
end

我想知道Ruby的元编程功能是否可用于生成这些类。但是,我很难创建 NAMES INSTANCES 和“enum-named”常量(例如 MON TUE ,...)。 const_set 的类方法,在此代码中它的上下文( self 的值)分别为几个月

创建工厂方法时,我不得不这样做:

def enum_new(names_array)
  Class.new do
    const_set "NAMES" []
    names_array.each_with_index do |name, idx|
      NAMES[idx] = name
    end
     ...
  end
end
Days = enum_new(%w| MON TUE ... |)
Months = enum_new(%w| JAN FEB ... |)

但这不起作用(至少,不像我希望的那样),因为 const_set 不会在名称为魔法的的类的上下文中被调用 set(即几个月),但显然是在 Class 的上下文中;因此,不仅无法从实例方法访问它,而且每次使用新的名称数组作为参数调用 enum_new 时,它都会被覆盖。使用类变量时会出现类似的问题,因为它们将在使用该方法生成的任何类之间共享(因为它们将成为 Class 的类变量,我猜)。

是否有任何方法可以在使用 Class.new 生成的类中创建常量,从而获得与原始月<< / strong>类,不必用几乎相同的类污染我的代码?

感谢您的关注和耐心! :)

1 个答案:

答案 0 :(得分:1)

是。在class_exec块中进行初始化,您可以在其中传递您的名称数据,self指向正确的类:

theClass=Class.new
theClass.class_exec(names) do |names|
  #initialize constants here...
end