2012-02-22 161 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 2012-02-22 22:33:37

+1

出於好奇,你解決了什麼問題?你如何計劃使用這些動態創建的類? – ctcherry 2012-02-22 22:38:05

+0

我的類被認爲是一個'框架',一旦被創建爲不適用於從yaml文件中實例化objetcs(只要它們滿足由該類設置的需求)。 YAML擁有一羣「人」,其中一些具有符合要求的屬性。 – BSG 2012-02-22 22:48:58

回答

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> 

從另一個類繼承,更換Struct.new通過Class.new(MyBaseClass),說:

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

我得到和錯誤,同時聲明克拉斯,名稱應該是一個常數,所以我大寫克拉斯在2,3行,現在它的工作。 – tebayoso 2014-08-28 13:24:43

+0

哦,對。修改示例。 – 2014-09-01 21:01:52

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

對不起,我在這裏真的超出了我的深度。你能不能請我解釋一下,好像我三歲? :p – BSG 2012-02-22 23:01:31

+1

我不確定這會更容易。第二種情況可能更容易理解:'eval'接受一個字符串,並在調用時評估*,就好像它是Ruby代碼一樣。所以,你在運行時用動態類的源代碼創建一個字符串,然後對其進行評估。第一種情況是創建一個新的類對象,爲它創建所需的方法等,然後給它一個名稱 - 在Ruby中與將類對象分配給常量相同。 – 2012-02-22 23:05:04