# How to create a class in callers context?

**URL:** <https://www.ruby-forum.com/t/how-to-create-a-class-in-callers-context/131077>\
**Category:** Ruby\
**Created:** [March 5, 2008, 8:50pm UTC](https://www.ruby-forum.com/t/how-to-create-a-class-in-callers-context/131077 "2008-03-05T20:50:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![DMisener](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@DMisener](https://www.ruby-forum.com/u/DMisener)\
**Post date:** [March 5, 2008, 8:50pm UTC](https://www.ruby-forum.com/t/how-to-create-a-class-in-callers-context/131077/1 "2008-03-05T20:50:56Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![DMisener](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@DMisener](https://www.ruby-forum.com/u/DMisener)\
**Post date:** [March 6, 2008, 2:35am UTC](https://www.ruby-forum.com/t/how-to-create-a-class-in-callers-context/131077/2 "2008-03-06T02:35:46Z")

</div>

> 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

---

<div class="post-metadata">

**Author:** ![DMisener](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@DMisener](https://www.ruby-forum.com/u/DMisener)\
**Post date:** [March 6, 2008, 6:16am UTC](https://www.ruby-forum.com/t/how-to-create-a-class-in-callers-context/131077/3 "2008-03-06T06:16:02Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![DMisener](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@DMisener](https://www.ruby-forum.com/u/DMisener)\
**Post date:** [March 6, 2008, 6:25am UTC](https://www.ruby-forum.com/t/how-to-create-a-class-in-callers-context/131077/4 "2008-03-06T06:25:45Z")

</div>

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
