Need help dynamically creating classes

I have a system at the moment where I create ‘things’ based on a base
class SceneObject, these ‘things’ have a Proc associated with them
that gets called to produce a different representation of the ‘thing’
(in my case data to be passed to a 3D renderer). At the moment it all
works like this…

class SceneObject
def initialize(&generate)
@generate = generate
end
def render
self.instance_eval(&@generate)
end
end

class MyObject < SceneObject
def initialize
super() do
# Render some objects
end
end
end

a = MyObject.new
a.render

This all works, but I’d like to ‘hide’ the class definition stuff, the
reason being that the data files passed through this system will be
defined outside, and don’t need to look like Ruby code, they 'use’
Ruby code to do the procedural stuff, but other than that I want them
to appear as simple as possible, so hiding classes, inheritance,
initialisation functions etc. would be a big benefit. Ideally I’d like
to do something like this, but can’t…

def defineClass(name,&generate)
eval <<-"end_eval"
class #{name} < SceneObject
def initialize
super(&#{generate})
end
end
end_eval
end

Then in my data files use this function like so…

defineClass(“MyObject”) do

Render some objects

end

a = MyObject.new
a.render

Can anyone offer any advice on how to achieve something like this?

Cheers

PaulG

defineClass("MyObject") do
  # Render some objects
end

a = MyObject.new
a.render

This is with ruby 1.7

pigeon% cat b.rb
#!./ruby

class SceneObject
   def initialize(&generate)
      @generate = generate
   end
   alias init initialize

   def render
      instance_eval(&@generate)
   end
end

def defineClass(name, &block)
   Object.const_set(name, Class.new(SceneObject)).instance_eval do
      define_method(:initialize) { init(&block) }
   end
end

defineClass("MyObject") do
   puts "render some object"
end

a = MyObject.new
a.render
pigeon%

pigeon% b.rb
render some object
pigeon%

Guy Decoux

Hi –

···

On Wed, 20 Nov 2002, ts wrote:

def render
instance_eval(&@generate)
end

Is there any difference (significant or otherwise) between this and:

def render
@generate.call
end

?

David


David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav

ts wrote:

“P” == Paul Gregory pgregory@aqsis.com writes:

defineClass(“MyObject”) do

Render some objects

end

a = MyObject.new
a.render

This is with ruby 1.7

pigeon% cat b.rb
#!./ruby

> > > Guy Decoux >

Brilliant, thanks, that is exactly what I needed.

Cheers

PaulG

ts decoux@moulon.inra.fr wrote in message news:200211191534.gAJFY0d16939@moulon.inra.fr

Next question: is it possible to specify arguments to the initialize
method when defining it with this code?

I’d like to be able to do something like…

defineClass(“MyObject”, scale) {
scale(scale)
puts(scale)
}

And have this define a class which takes one argument in its
constructor, then use it thus…

a = MyObject.new(1.5)

Cheers

PaulG

Is there any difference (significant or otherwise) between this and:

  def render
    @generate.call
  end

Yes, self :slight_smile:

pigeon% cat b.rb
#!./ruby

class SceneObject
   def initialize(&generate)
      @generate = generate
   end
   alias init initialize

   def render
      instance_eval(&@generate)
   end

   def rendernot
      @generate.call
   end
end

def defineClass(name, &block)
   Object.const_set(name, Class.new(SceneObject)).instance_eval do
      define_method(:initialize) { init(&block) }
   end
end

defineClass("MyObject") do
   puts "render some object #{self}"
end

a = MyObject.new
a.render
a.rendernot
pigeon%

pigeon% b.rb
render some object #<MyObject:0x401abb78>
render some object main
pigeon%

Guy Decoux

Brilliant, thanks, that is exactly what I needed.

Well, I don't really know what you want to do, and I've tried to do what
you want but personnally I'll write it like this

pigeon% cat b.rb
#!/usr/bin/ruby

class SceneObject

   class << self
      attr_accessor :generate
   end

   def render
      instance_eval(&type.generate)
   end

end

def defineClass(name, &block)
   Object.const_set(name, Class.new(SceneObject)).generate = block
end

defineClass("MyObject") do
   puts "render some object #{self}"
end

a = MyObject.new
a.render
pigeon%

pigeon% b.rb
render some object #<MyObject:0x401ad1f8>
pigeon%

I don't know why but it seems more natural, for me, to have a class
instance variable rather than try to call #initialize

Guy Decoux

Next question: is it possible to specify arguments to the initialize
method when defining it with this code?

Well, you can write

pigeon% cat b.rb
#!./ruby

class SceneObject
   def initialize(scale, &generate)
      @scale = scale
      @generate = generate
   end
   alias init initialize

   def render
      instance_eval(&@generate)
   end
end

def defineClass(name, &block)
   Object.const_set(name, Class.new(SceneObject)).instance_eval do
      define_method(:initialize) {|scale| init(scale, &block) }
   end
end

defineClass("MyObject") do
   puts "render some object #{self.inspect}"
end

a = MyObject.new(1.5)
a.render
pigeon%

pigeon% b.rb
render some object #<MyObject:0x401abc2c @generate=#<Proc:0x401abd30@./b.rb:21>, @scale=1.5>
pigeon%

I'd like to be able to do something like...

defineClass("MyObject", scale) {
    scale(scale)
    puts(scale)
}

but in this case you must write it

   defineClass("MyObject") {
      scale(@scale)
      puts(@scale)
   }

Or you can make someting more complex

pigeon% cat b.rb
#!./ruby

class SceneObject
   def initialize(params, &generate)
      params.each do |k, v|
         class << self; self end.send(:attr_accessor, k)
         send("#{k}=", v)
      end
      @generate = generate
   end
   alias init initialize

   def render
      instance_eval(&@generate)
   end
end

def defineClass(name, var, &block)
   Object.const_set(name, Class.new(SceneObject)).instance_eval do
      define_method(:initialize) {|scale| init(var => scale, &block) }
   end
end

defineClass("MyObject", "scale") do
   puts "render some object #{self.inspect}"
   p self.scale
end

a = MyObject.new(1.5)
a.render
pigeon%

pigeon% b.rb
render some object #<MyObject:0x401ab7e0 @scale=1.5, @generate=#<Proc:0x401ab8f8@./b.rb:24>>
1.5
pigeon%

but you must prefix `scale' with `self.' otherwise ruby interpret it as a
local variable.

Guy Decoux

         class << self; self end.send(:attr_accessor, k)

This is stupid, there is a better way

pigeon% cat b.rb
#!./ruby

class SceneObject
   def initialize(params, &generate)
      params.each do |k, v|
         k.each_with_index do |name, i|
            send("#{name}=", v[i])
         end
      end
      @generate = generate
   end
   alias init initialize

   def render
      instance_eval(&@generate)
   end
end

def defineClass(name, *var, &block)
   Object.const_set(name, Class.new(SceneObject)).instance_eval do
      var.each {|v| send(:attr_accessor, v)}
      define_method(:initialize) {|*scale| init(var => scale, &block) }
   end
end

defineClass("MyObject", "scale") do
   puts "render some object #{self.inspect}"
end

a = MyObject.new(1.5)
a.render

defineClass("MyObject2", "scale1", "scale2") do
   puts "render another object #{self.inspect}"
end

a = MyObject2.new(1.5, 3.0)
a.render
pigeon%

pigeon% b.rb
render some object #<MyObject:0x401ab31c @generate=#<Proc:0x401ab498@./b.rb:26>, @scale=1.5>
render another object #<MyObject2:0x401aafd4 @scale1=1.5, @generate=#<Proc:0x401ab2a4@./b.rb:33>, @scale2=3.0>
pigeon%

Guy Decoux

ts wrote:

“t” == ts decoux@moulon.inra.fr writes:

     class << self; self end.send(:attr_accessor, k)

This is stupid, there is a better way

Spot on! Thanks, that is exactly the sort of thing I’m after.

In case you are interested in what I am trying to achieve, I am trying
to make a procedural animation system based around Renderman. Similar in
principle to WavesWorld by Michael B. Johnson, and AL my Steve May.

Basincally you define your objects in terms of code segments, which
(when I get round to this bit) have links to avars (animated variables)
which can be altered over time by various methods, then by adjusting
these avars, and regenerating the scene sections which rely on them, you
get a powerful animation system.

Long way off yet tho’ still just planning and throwing ideas around.

cheers

PaulG

Oh my word! YES, I am interested!!! I have always wanted
to do this. I loved WavesWorld and attempted to do the same
thing in Perl, but didn’t put enough time into it.
I’m the author of the RenderMan binding for Perl, by the way,
and have now seen the light with Ruby after 10+ years
programming in Perl.

Please keep us (or at least me) posted on your progress, Paul!
Thanks!
– Glenn Lewis

Paul Gregory wrote:

···

In case you are interested in what I am trying to achieve, I am trying
to make a procedural animation system based around Renderman. Similar in
principle to WavesWorld by Michael B. Johnson, and AL my Steve May.

Basincally you define your objects in terms of code segments, which
(when I get round to this bit) have links to avars (animated variables)
which can be altered over time by various methods, then by adjusting
these avars, and regenerating the scene sections which rely on them, you
get a powerful animation system.

Long way off yet tho’ still just planning and throwing ideas around.

cheers

PaulG