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?
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>
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