Creating a class dynamically

2020-02-23 06:50发布

I'm trying to create a new class, without knowing the name of the class until it's supposed to på created.

Something like this;

    variable = "ValidClassName"

        class variable

        end

Test = ValidClassName.new

If possible, i'd also appreciate som hints on how to dynamically add attributes (and methods) to this new class.

I'll be retreiving 'settings' for the class, and they will look something like this:

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

But should not be designed to accept only that explicit file, the attributes might differ in number end type.

Which in the end will generate a class that should look something like:

class Person
   def initialize(name, age)

       @name_out = name
       @age_out = age
   end

end

Help?

2条回答
Anthone
2楼-- · 2020-02-23 07:28

A class gains its name when it is assigned to a constant. So It's easy to do in a generic fashion with const_set.

For example, let's say you want to use Struct to build a class with some attributes, you can:

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>

To inherit from another class, replace the Struct.new by Class.new(MyBaseClass), say:

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> 
查看更多
兄弟一词,经得起流年.
3楼-- · 2020-02-23 07:37

Your code would look something akin to this:

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)

...or you could just use eval:

eval <<DYNAMIC
  class #{name}
    title :Person
    attribute :name, String
    # ...or substitute other stuff in here.
  end
DYNAMIC
查看更多
登录 后发表回答