私はRuby(1.9.3)で小さなコードを書いています。そして、 const_setでいくつかの定数を定義し、これらの定数のいくつかの動作を定義する、単純な「列挙型」クラスのペアを使用します(たとえば、クラスDaysは定数MON、TUE ...およびDays:: MON.succはTUEに評価される必要があります)。
私はこれらのクラスに本当に満足しています。ただし、コードを成長させている間、それらをさらに追加する必要がある場合があり、ソースコードの99%を共有する5つ以上のクラスを作成するというアイデアは好きではありません。
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、および「列挙型」定数(MON、TUEなど)を作成するのに苦労しています。const_setであるClassのクラスメソッドであるため、このコードでは、そのコンテキスト(selfの値)はそれぞれDaysとMonthsです。
ファクトリメソッドを作成するとき、私は次のようなことを強いられます。
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は、名前が魔法のように設定されているクラス(つまり、 DaysとMonths)のコンテキストでは呼び出されないため、明らかにClassのコンテキストで呼び出されます。 ; したがって、インスタンスメソッドからアクセスできないだけでなく、引数として名前の新しい配列を使用してenum_newが呼び出されるたびに上書きされます。クラス変数を使用する場合にも同様の問題が発生します。これは、メソッドで生成されたすべてのクラス間で共有されるためです(Classのクラス変数になるためです)。
Class.newで生成されたクラスに定数を作成し、コードをほとんど同じクラスで汚染することなく、元のDaysおよびMonthsクラスとすべて同じクラスを取得する方法はありますか?
ご清聴ありがとうございました!:)