How to create a class in callers context?

Here’s a simple example of my predicament:

class Factory
def self.generate name,_binding
_name=name.to_s.capitalize
eval %[
class #{_name}
def to_s
“#{_name}”
end
end
],_binding
end
end

def Factory_generate what
Factory.generate what,binding
end

Factory_generate :Thing
puts Factory::Thing.new rescue puts “Can’t
Factory::Thing.new” # warning
puts Thing .new rescue puts “Can’t Thing.new”

class Universe
def initialize
Factory_generate :Planet
puts Universe::Planet.new rescue puts “Can’t
Universe::Planet.new” # warning
puts Planet .new rescue puts “Can’t Planet.new”
end
end

Universe.new

puts Universe::Planet.new rescue puts “Can’t
Universe::Planet.new” # warning
puts Planet .new rescue puts “Can’t Planet.new”


results in the following surprising output:

C:/Work/class_eval.rb:20: warning: toplevel constant Thing referenced
by Factory::Thing
Thing
Thing
C:/Work/class_eval.rb:26: warning: toplevel constant Planet referenced
by Universe::Planet
Planet
Planet
C:/Work/class_eval.rb:33: warning: toplevel constant Planet referenced
by Universe::Planet
Planet
Planet

Questions:

  1. What’s the correct way to doing this?
  2. I would have thought the non-qualified class references would have
    generated exceptions.
  3. What is the warning message trying to convey.
  1. What’s the correct way to doing this?

Don’t know the “correct” way, there is always more than one form to do
it. This is what I would do

class Class
def generate(name)
klass = Class.new
klass.class_eval <<-EVAL
def to_s
“I’m a #{name}”
end
EVAL
const_set(name, klass)
end
end

class Universe
generate :Planet
puts Planet.new
puts Universe::Planet.new
end

puts Planet.rescue “No Planet!”
puts Universe::Planet.new


I’m a Planet
I’m a Planet
No Planet!
I’m a Planet


alternatively you could do

klass = Class.new do
def foo
#…
end
end

but then you can’t pass a reference to the variable name. Don’t know
if there’s a way do do it, though.

If I wanted that to stick on a method, I would pass the binding as
well

class Factory
def self.generate(name, _binding)
eval <<-EVAL, _binding
class #{name}
def to_s
“Hello from #{name}”
end
end
EVAL
end
end

  1. I would have thought the non-qualified class references would have
    generated exceptions.

Very intriguing. I would have expected the same

DMisener wrote:

  1. What’s the correct way to doing this?
  2. I would have thought the non-qualified class references would have
    generated exceptions.
  3. What is the warning message trying to convey.

Here’s my crack at this, not sure this is what you’re trying to do:

def generate &name
eval(“self”,name.binding).class.class_eval <<-EOS
class #{name.call}
def to_s
name.call
end
end
EOS
end

class Universe
def initialize
generate{:Planet}
puts Universe::Planet
end
end

generate{:Thing}

Universe.new
puts Thing

Drew O. wrote:

DMisener wrote:

  1. What’s the correct way to doing this?
  2. I would have thought the non-qualified class references would have
    generated exceptions.
  3. What is the warning message trying to convey.

Here’s my crack at this, not sure this is what you’re trying to do:

Had a small typo, here’s the fixed example:

def generate &name
eval(“self”,name.binding).class.class_eval <<-EOS
class #{name.call}
def to_s
“#{name.call}”
end
end
EOS
end

class Universe
def initialize
generate{:Planet}
end
end

generate{:Thing}

Universe.new

puts Universe::Planet.new
puts Thing.new