2015-11-01 172 views
3

我想动态创建一组类,如下所示。 Ruby:动态创建新类

class Foo 
    attr_reader :description 
end 

['Alpha', 'Beta', 'Gamma'].each do |i| 
    klass = Class.new(Foo) do |i| 
    def initialize 
     @description = i 
    end 
    end 
    Object.const_set(i, klass) 
end 

而不是手动创建每个类, g .:

class Alpha < Foo 
    def initialize 
    @description = 'Alpha' 
    end 
end 

什么是正确的方式来做这样的事情,以及如何将迭代器传递到嵌套块?

回答

1

我如何通过一个迭代器嵌套块?

通过使用嵌套。 def不是一个块。 def会切断def之外的变量的可见性。在另一方面,一个可以看到块外的变量:

class Foo 
    attr_reader :description 
end 

['Alpha', 'Beta', 'Gamma'].each do |class_name| 
    klass = Class.new(Foo) do 
    define_method(:initialize) do 
     @description = class_name 
    end 
    end 

    Object.const_set(class_name, klass) 
end 

a = Alpha.new 
p a.description 

--output:-- 
"Alpha" 

你也可以做你想做的,而无需创建一个嵌套的块或类Foo:

['Alpha', 'Beta', 'Gamma'].each do |class_name| 
    klass = Class.new() do 
    def initialize 
     @description = self.class.name 
    end 

    attr_reader :description 

    end 

    Object.const_set(class_name, klass) 
end 

--output:-- 
"Alpha" 
"Gamma" 
+0

'@description = self.class.name'可以使用或不使用父类。这是一个很好的解决方案! – mwp

1

你很近。我想你想让description成为一个类实例变量(或可能是一个类变量),而不是一个实例变量。对于Alpha类的所有对象,description将为“Alpha”,因此它应该是该类的一个属性。您可以将其作为Alpha.description(或Alpha.new.class.description)访问。下面是使用一个类的实例变量的解决方案:

class Foo 
    class << self 
    attr_reader :description 
    end 
end 

['Alpha', 'Beta', 'Gamma'].each do |i| 
    klass = Class.new(Foo) 
    klass.instance_variable_set(:@description, i) 

    Object.const_set(i, klass) 
end 
+0

伟大的答案+1 – illusionist

+0

*对于Alpha类的所有对象,描述将是“Alpha”,因此它应该是该类的一个属性。* - 不一定...因为对类实例*变量的更改将影响所有实例看到的内容。另一方面,如果变量是在'initialize()'内部创建的,那么每个实例都有自己的变量,并且可以独立于其他实例进行更改。 – 7stud

+0

确实如此,但我们将描述设置为类的名称,所以如果这是OP要执行的断言,则对于该类的所有实例而言,这将是相同的。如果OP希望能够灵活地将实例的描述设置为稍后的其他内容,那么是的,您的方法效果更好。 – mwp

1
class Foo 
    attr_reader :description 
end 

['Alpha', 'Beta', 'Gamma'].each do |class_name| 
    eval %Q{ 
    class #{class_name} < Foo 
     def initialize 
     @description = #{class_name} 
     end 
    end 
    } 
end 

在执行:

Gamma.new.description 
=> Gamma