0

我正在用 Ruby (1.9.3) 编写一小段代码,我使用了一对简单的“类枚举”类,它们用const_set定义了一些常量以及这些常量的一些行为(例如Days类可能有常量MONTUE ... 和Days::MON.succ应该评估为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 的元编程功能来生成这些类。但是,我很难创建NAMESINSTANCES和“枚举命名”常量(例如MONTUE、...)。作为const_set的类方法Class,在这段代码中,它的上下文(self的值)分别是DaysMonths

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

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不会在名称被神奇设置的类的上下文中调用(即DaysMonths),但显然是在Class的上下文中; 因此,不仅不能从实例方法访问它,而且每次使用新的名称数组作为参数调用enum_new时,它都会被覆盖。使用类变量时会出现类似的问题,因为它们将在使用该方法生成的任何类之间共享(因为它们将成为Class的类变量,我猜)。

有没有办法在使用Class.new生成的类中创建常量,以这种方式获得与原始DaysMonths类相同的类,而不必用几乎相同的类污染我的代码?

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

4

1 回答 1

1

是的。class_exec在一个块中进行初始化,您可以将您的名称数据传递到其中,其中self引用正确的类:

theClass=Class.new
theClass.class_exec(names) do |names|
  #initialize constants here...
end
于 2012-04-30T15:44:49.363 回答