2012-04-30 4 views
0

Ruby(1.9.3)に少しのコードを書いていますが、いくつかの定数を定義する単純な列挙型クラスのペアを使用します。const_setそしてこれらの定数の一部の動作(例えばクラスに火評価すべき定数 ...と日:: MON.succを有していてもよいです)。Class.newで作成されたクラスの定数

私はこれらのクラスで本当に快適です。私のコードを成長させながら、しかし、例えば、私は時々それらの多くを追加する必要がある、と私は、ソースコードの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のメタプログラミング機能を使用できるかどうか。しかし、私はNAMESINSTANCESと "列挙ネーム" 定数(例えば、...)の作成に苦労しています。 クラス、このコードでは、コンテキスト(自己の値)だのクラスメソッドconst_setであることは、それぞれです。

ファクトリメソッドを作成するときに、私はこのような何かを余儀なくよ:

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ウォン「トン名前魔法セット(すなわちあるクラスのコンテキストで呼び出されるが、どうやらクラスの文脈で。したがって、インスタンスメソッドからはアクセスできないだけでなく、新しい名前の配列を引数として呼び出すたびに、それが上書きされます。enum_newが呼び出されます。同様の問題は、クラス変数を使用するときに表示されます。その理由は、メソッドで生成されたクラス間で共有されるからです(クラス変数クラスとなるためです)。

ヶ月間ほぼ同じで自分のコードを汚染することなくクラスにすべてのクラスと同じこの方法を取得し、Class.newで生成されたクラスの定数を作成するにはどのような方法がありますクラス?

あなたの注意と忍耐ありがとう! :)

+0

あなたはあなたの省略記号を放出するコードを記入してくださいことはできますか? – Linuxios

+0

私はファーストクラスのコードを完成させ、インスタンスメソッドの定数にどのようにアクセスする必要があるかを示す2つのサンプル操作を追加しました。もちろん、インスタンスはconst_setで作成された定数を介してアクセスされます。 –

答えて

1

はい。あなたの名前データを渡し、selfが正しいクラスを参照することができますそこにclass_execブロック、中にあなたの初期化を行います。

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

ありがとう、これは実際に私が欲しいものを正確に行ういくつかの作業コードに私をもたらしました。しかし、** class_exec **に関連付けられたブロックで 'name '、value'を' const_set'した場合、同じブロック内で** NAME **を 'self :: NAME'と呼ぶ必要があることに気付きました。 ** self.class :: NAME'は** Class.new **に関連するブロックにあります。 ** self **を明示的に参照するだけの特別な理由はありますか? ** class_exec **に関連付けられたブロックの定数名がグローバル定数を参照するのはなぜですか? –

+0

彼らはしません。 'class_exec'は、通常のクラス定義の' class'と 'end'の間の場所と考えることができます。 'self'を使わなければならないという事実は、それを定数に代入するまで、クラスは事実上無名であり、' self'オブジェクトか*変数* 'theClass'からアクセスされなければならないからです。定数(例えば 'Days')に代入すると、' Days :: MON'で物事にアクセスできます。 – Linuxios

+0

私の意味は、コード 'NAMES = ['nothing']です。クラスA;名前= ['foo'];終わり; A.class_exec {NAMES [0] = 'bar'}; p NAMES [0] 'は_bar_を出力します。名前付きクラスで 'class_exec'を使用していますが、関連するブロックで使用される定数名は' A'クラスではなくグローバル定数 'NAMES'を参照しています。これは私が期待していなかった振る舞いです。 –

関連する問題