在Ruby中动态创建类

我有一个类应该看起来像这样:

class Family_Type1 @people = Array.new(3) @people[0] = Policeman.new('Peter', 0) @people[1] = Accountant.new('Paul', 0) @people[2] = Policeman.new('Mary', 0) def initialize(*ages) for i in 0 ... @people.length @people[i].age = ages[i] end end end 

我希望能够在运行时定义一组类似于这一类的类(在启动时定义它们一次),其中数组的大小和分配给每个参数的类型在运行时从外部规范文件定义。

我有点使用evals工作,但这真的很难看。 有更好的方法吗?

首先,您的示例代码不适合您的部分原因是您有两个不同的@people变量 – 一个是实例变量 ,另一个是类实例变量

 class Example # we're in the context of the Example class, so # instance variables used here belong to the actual class object, # not instances of that class self.class #=> Class self == Example #=> true @iv = "I'm a class instance variable" def initialize # within instance methods, we're in the context # of an _instance_ of the Example class, so # instance variables used here belong to that instance. self.class #=> Example self == Example #=> false @iv = "I'm an instance variable" end def iv # another instance method uses the context of the instance @iv #=> "I'm an instance variable" end def self.iv # a class method, uses the context of the class @iv #=> "I'm a class instance variable" end end 

如果要在类中创建一次变量以在该类的实例方法中使用,请使用constantsclass variables

 class Example # ruby constants start with a capital letter. Ruby prints warnings if you # try to assign a different object to an already-defined constant CONSTANT_VARIABLE = "i'm a constant" # though it's legit to modify the current object CONSTANT_VARIABLE.capitalize! CONSTANT_VARIABLE #=> "I'm a constant" # class variables start with a @@ @@class_variable = "I'm a class variable" def c_and_c [ @@class_variable, CONSTANT_VARIABLE ] #=> [ "I'm a class variable", "I'm a constant" ] end end 

即便如此,在代码的上下文中,您可能不希望所有Family_Type1实例都引用相同的警察和会计师吗? 或者你呢?

如果我们切换到使用类变量:

 class Family_Type1 # since we're initializing @@people one time, that means # all the Family_Type1 objects will share the same people @@people = [ Policeman.new('Peter', 0), Accountant.new('Paul', 0), Policeman.new('Mary', 0) ] def initialize(*ages) @@people.zip(ages).each { |person, age| person.age = age } end # just an accessor method def [](person_index) @@people[person_index] end end fam = Family_Type1.new( 12, 13, 14 ) fam[0].age == 12 #=> true # this can lead to unexpected side-effects fam2 = Family_Type1.new( 31, 32, 29 ) fam[0].age == 12 #=> false fam2[0].age == 31 #=> true fam[0].age == 31 #=> true 

正如Chirantan所说,运行时初始化可以通过元编程完成,但是如果你只是初始化几个类,并且你知道他们的名字是什么,你也可以通过使用从文件中读取的任何内容来完成:

 PARAMS = File.read('params.csv').split("\n").map { |line| line.split(',') } make_people = proc do |klasses, params| klasses.zip(params).map { |klass,name| klass.new(name, 0) } end class Example0 @@people = make_people([ Fireman, Accountant, Fireman ], PARAMS[0]) end class Example1 @@people = make_people([ Butcher, Baker, Candlestickmaker ], PARAMS[0]) end 

据我所知,你需要元编程。 下面是一段代码片段,用于动态创建类(动态),初始化方法初始化实例变量 –

 class_name = 'foo'.capitalize klass = Object.const_set(class_name,Class.new) names = ['instance1', 'instance2'] # Array of instance vars klass.class_eval do attr_accessor *names define_method(:initialize) do |*values| names.each_with_index do |name,i| instance_variable_set("@"+name, values[i]) end end # more... end 

希望你能调整它以满足你的要求。

假设您想在运行时为每个类型/数组大小创建不同的类

如果(就像在Python中)在执行时定义了一个Ruby类(我认为是),那么你可以这样做:

在函数内定义您的类。 让函数接收数组大小和类型作为参数,并在其结果中返回类。 这样,你有一个类工厂来调用你的spec文件中的每个定义:)

另一方面,如果您想根据实际数据初始化@params ,请记住,Ruby是一种动态类型语言:只需将构造函数中的@params重新分配给新数组即可!