2012-02-22 14 views
9

クラスの名前がわからなくても、新しいクラスを作成しようとしています。クラスを動的に作成する

このようなものです。可能であれば

variable = "ValidClassName" 

     class variable 

     end 

Test = ValidClassName.new 

は、私はまた、動的にこの新しいクラスに属性(とメソッド)を追加する方法についてソムヒントをいただければと思います。

私はクラスのための「設定」をretreivingされます、そして、彼らはこのようなものになります。

title :Person 
attribute :name, String 
attribute :age, Fixnum 

しかし、それだけで明示的にファイルを受け入れるように設計されるべきではありませんが、属性は、数の末尾に異なる場合がありますタイプ。

class Person 
    def initialize(name, age) 

     @name_out = name 
     @age_out = age 
    end 

end 

ヘルプ:最後にようになっているはずクラスを生成します

+1

クラスのソースコードを作成したいだけですか?またはあなたはソースを生成し、実行時にクラスをコンパイル/ロードするようにrubyに伝えたいですか? – ardnew

+1

好奇心から、あなたはどんな問題を解決していますか?どのようにこれらの動的に作成されたクラスを使用する予定ですか? – ctcherry

+0

私のクラスはyamlファイルからobjetcsをインスタンス化するために使い慣れていれば(クラスによって設定された要求を満たしている限り)、 'フレーム'として機能するはずです。 YAMLには多数の「人」があり、その中には要件に合致する属性を持つものがあります。 – BSG

答えて

23

クラスは、その名前を得ます。だから、const_setで一般的なやり方で行うのは簡単です。

たとえば、あなたができる、あなたはいくつかの属性を持つクラスを構築するためにStructを使用したいとしましょう:

name = "Person" 
attributes = [:name, :age] 

klass = Object.const_set name, Struct.new(*attributes) 
# Now use klass or Person or const_get(name) to refer to your class: 
Person.new("John Doe", 42) # => #<struct Person name="John Doe", age=42> 

Class.new(MyBaseClass)Struct.newを置き換える、別のクラスから継承するには、言う:

class MyBaseClass; end 

klass = Class.new(MyBaseClass) do 
    ATTRIBUTES = attributes 
    attr_accessor *ATTRIBUTES 
    def initialize(*args) 
    raise ArgumentError, "Too many arguments" if args.size > ATTRIBUTES.size 
    ATTRIBUTES.zip(args) do |attr, val| 
     send "#{attr}=", val 
    end 
    end 
end 
Object.const_set name, klass 
Person.new("John Doe", 42) # => #<Person:0x007f934a975830 @name="John Doe", @age=42> 
+0

klassを宣言している間にエラーが出ていますが、名前は定数でなければなりません。したがって、klassを2,3行でKlassに大文字にしました。 – tebayoso

+0

ああ、そうです。変更例 –

6

あなたのコードは、これに似た何かになります:

variable = "SomeClassName" 
klass = Class.new(ParentClass) 
# ...maybe evaluate some code in the context of the new, anonymous class 
klass.class_eval { } 
# ...or define some methods 
klass.send(:title, :Person) 
klass.send(:attribute, :name, String) 
# Finally, name that class! 
ParentClass.send(:const_set, variable, klass) 

を...またはあなただけのevalを使用することができます。それが定数に割り当てられている場合

eval <<DYNAMIC 
    class #{name} 
    title :Person 
    attribute :name, String 
    # ...or substitute other stuff in here. 
    end 
DYNAMIC 
+1

申し訳ありませんが、私は本当にここで私の深さから外れています。私が3歳であるかのように説明してください。 :p – BSG

+1

これははるかに簡単になるか分かりません。 2番目のケースはおそらく分かりやすいでしょう。 'eval'は文字列をとり、呼び出し時にRubyコードのように*評価します。したがって、実行時に動的クラスのソースコードを含む文字列を作成し、それを評価します。最初のケースでは、新しいクラスオブジェクトを作成し、目的のメソッドなどを作成するためにそれを行い、それに名前を付けます。これは、クラスオブジェクトを定数に割り当てることと同じです。 –