2012-02-22 99 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