Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Need help dynamically creating classes.

137 views
Skip to first unread message

Paul Gregory

unread,
Nov 19, 2002, 9:45:35 AM11/19/02
to
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

ts

unread,
Nov 19, 2002, 10:35:31 AM11/19/02
to
>>>>> "P" == Paul Gregory <pgre...@aqsis.com> writes:

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

P> a = MyObject.new
P> 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

dbl...@candle.superlink.net

unread,
Nov 19, 2002, 10:43:36 AM11/19/02
to
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: dbl...@candle.superlink.net
work: blac...@shu.edu
Web: http://pirate.shu.edu/~blackdav


ts

unread,
Nov 19, 2002, 10:47:09 AM11/19/02
to
>>>>> "d" == dblack <dbl...@candle.superlink.net> writes:

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

d> def render
d> @generate.call
d> end

Yes, self :-)


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


Paul Gregory

unread,
Nov 19, 2002, 6:43:28 PM11/19/02
to
ts wrote:
>>>>>>"P" == Paul Gregory <pgre...@aqsis.com> writes:
>>>>>
>
> P> defineClass("MyObject") do
> P> # Render some objects
> P> end
>
> P> a = MyObject.new
> P> a.render
>
> This is with ruby 1.7
>
> pigeon% cat b.rb
> #!./ruby
>
<snip>
>
>
> Guy Decoux
>

Brilliant, thanks, that is exactly what I needed.

Cheers

PaulG

ts

unread,
Nov 20, 2002, 5:19:26 AM11/20/02
to
>>>>> "P" == Paul Gregory <pgre...@aqsis.com> writes:

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

Paul Gregory

unread,
Nov 20, 2002, 9:09:46 AM11/20/02
to
ts <dec...@moulon.inra.fr> wrote in message news:<200211191534...@moulon.inra.fr>...

> >>>>> "P" == Paul Gregory <pgre...@aqsis.com> writes:
>

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

ts

unread,
Nov 20, 2002, 9:36:53 AM11/20/02
to
>>>>> "P" == Paul Gregory <pgre...@aqsis.com> writes:

P> Next question: is it possible to specify arguments to the initialize
P> 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%

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

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

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

ts

unread,
Nov 20, 2002, 9:48:58 AM11/20/02
to
>>>>> "t" == ts <dec...@moulon.inra.fr> writes:

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


Paul Gregory

unread,
Nov 20, 2002, 2:17:47 PM11/20/02
to
ts wrote:
>>>>>>"t" == ts <dec...@moulon.inra.fr> writes:
>>>>>
>
> t> 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

Glenn M. Lewis

unread,
Nov 20, 2002, 4:02:50 PM11/20/02
to
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

0 new messages