Dynamic Class Definition WITH a Class Name
The name of a class is simply the name of the first constant that refers to it.
I.e. if I do myclass = Class.new
and then MyClass = myclass
, the name of the class will become MyClass
. However I can't do MyClass =
if I don't know the name of the class until runtime.
So instead you can use Module#const_set
, which dynamically sets the value of a const. Example:
dynamic_name = "ClassName"Object.const_set(dynamic_name, Class.new { def method1() 42 end })ClassName.new.method1 #=> 42
I've been messing around with this too. In my case I was trying to test extensions to ActiveRecord::Base. I needed to be able to dynamically create a class, and because active record looks up a table based on a class name, that class couldn't be anonymous.
I'm not sure if this helps your case, but here's what I came up with:
test_model_class = Class.new(ActiveRecord::Base) do def self.name 'TestModel' end attr_accessor :foo, :barend
As far as ActiveRecord is concerned, defining self.name was enough. I'm guessing this will actually work in all cases where a class cannot be anonymous.
(I've just read sepp2k's answer and I'm thinking his is better. I'll leave this here anyway.)
I know this is a really old question, and some other Rubyists might shun me from the community for this, but I am working on creating a very thin wrapper gem that wraps a popular java project with ruby classes. Based on @sepp2k's answer, I created a couple helper methods because I had to do this many, many times in one project. Note that I namespaced these methods so that they were not polluting some top-level namespace like Object or Kernel.
module Redbeam # helper method to create thin class wrappers easily within the given namespace # # @param parent_klass [Class] parent class of the klasses # @param klasses [Array[String, Class]] 2D array of [class, superclass] # where each class is a String name of the class to create and superclass # is the class the new class will inherit from def self.create_klasses(parent_klass, klasses) parent_klass.instance_eval do klasses.each do |klass, superklass| parent_klass.const_set klass, Class.new(superklass) end end end # helper method to create thin module wrappers easily within the given namespace # # @param parent_klass [Class] parent class of the modules # @param modules [Array[String, Module]] 2D array of [module, supermodule] # where each module is a String name of the module to create and supermodule # is the module the new module will extend def self.create_modules(parent_klass, modules) parent_klass.instance_eval do modules.each do |new_module, supermodule| parent_klass.const_set new_module, Module.new { extend supermodule } end end endend
To use these methods (note that this is JRuby):
module Redbeam::Options Redbeam.create_klasses(self, [ ['PipelineOptionsFactory', org.apache.beam.sdk.options.PipelineOptionsFactory] ]) Redbeam.create_modules(self, [ ['PipelineOptions', org.apache.beam.sdk.options.PipelineOptions] ])end
WHY??
This allows me to create a JRuby gem that uses the Java project and would allow the open source community and I to decorate these classes in the future, as necessary. It also creates a more friendly namespace to use the classes in. Since my gem is a very, very thin wrapper, I had to create many, many subclasses and modules to extend other modules.
As we say at J.D. Power, "this is apology-driven development: I'm sorry".