Creating classes on the fly

Greetings again! I'm trying to create a user-defined class on the fly.
The idea would be for the user to provide a class name, maybe a
superclass name, and some method definition as a string, e.g.

  str1 = "MyClass"
  str2 = "Class"
  str3 = "def bar \n p \"bar!\" \n end"

and then my program would perhaps do something like

  eval "class #{str1} < #{str2}\n #{str3} \n end"

So far so good. Security is not a concern, this is just for a proof of
concept. But I would like to be able to then extend MyClass
separately, e.g.

  module Mod
    def bar
       p "foo!"
    end
  end

  class ???
     include Mod
  end

I'm stuck on the ??? part. I tried

  class eval( str1 )

I tried

  class str.intern # (I think I know by now why this one was a stupid idea)

I tried

  $myclassref = eval str1
  class $myclassref

All to no avail. So I'm wondering whether I'm trying to do this the
wrong way. What would be the Ruby way of solving this problem?

Sam

···

On Sun, 15 Aug 2004 04:31:11 +0900, Claus Spitzer <docboobenstein@gmail.com> wrote:

I'm stuck on the ??? part. I tried

  class eval( str1 )

I tried

  class str.intern # (I think I know by now why this one was a stupid idea)

I tried

  $myclassref = eval str1
  class $myclassref

All to no avail. So I'm wondering whether I'm trying to do this the
wrong way. What would be the Ruby way of solving this problem?

klass = eval(str1)
klass.class_eval do
  include Mod
end

To give you a better idea of what I was looking for, I'm trying to do
the Ruby equivalent of this Smalltalk code

  >myClassname myCat myClass|
  myCat := 'Foo Classes'.
  myClassname := 'MyClass'.
  (Smalltalk hasClassNamed: myClassname) ifTrue: [Smalltalk
removeClassNamed: myClassname].
  (Smalltalk organization) addCategory:myCat before: 'Kernel-Methods'.
  (ClassBuilder new) superclass:Object subclass: (myClassname
asSymbol) instanceVariableNames:''
                    classVariableNames: '' poolDictionaries: '' category: myCat.

  myClass := Smalltalk classNamed: myClassname.

  myClass addInstVarName: 'x';addClassVarName: 'X'.

  (myClass respondsTo: ('getx' asSymbol)) ifFalse:[
              myClass compile: 'getx
                  ^ x' classified: 'accessors'].
  (myClass canUnderstand: ('getX' asSymbol)) ifFalse:[
              myClass compile: 'getX
                  ^ X' classified: 'accessors'].
               
  Transcript clear;show: (myClass definition).
  Transcript cr;show: (myClass selectors).
  (myClass new) perform: ('getx' asSymbol); perform: ('getX' asSymbol).

Cheers!
  -CWS

···

On Sat, 14 Aug 2004 15:30:57 -0400, Claus Spitzer <docboobenstein@gmail.com> wrote:

Greetings again! I'm trying to create a user-defined class on the fly.
The idea would be for the user to provide a class name, maybe a
superclass name, and some method definition as a string, e.g.

  str1 = "MyClass"
  str2 = "Class"
  str3 = "def bar \n p \"bar!\" \n end"

and then my program would perhaps do something like

  eval "class #{str1} < #{str2}\n #{str3} \n end"

So far so good. Security is not a concern, this is just for a proof of
concept. But I would like to be able to then extend MyClass
separately, e.g.

  module Mod
    def bar
       p "foo!"
    end
  end

  class ???
     include Mod
  end

I'm stuck on the ??? part. I tried

  class eval( str1 )

I tried

  class str.intern # (I think I know by now why this one was a stupid idea)

I tried

  $myclassref = eval str1
  class $myclassref

All to no avail. So I'm wondering whether I'm trying to do this the
wrong way. What would be the Ruby way of solving this problem?

Greetings again! I'm trying to create a user-defined class on the fly.
The idea would be for the user to provide a class name, maybe a
superclass name, and some method definition as a string, e.g.

[...]

So far so good. Security is not a concern, this is just for a proof of
concept. But I would like to be able to then extend MyClass
separately, e.g.

  module Mod
    def bar
       p "foo!"
    end
  end

  class ???
     include Mod
  end

I'm stuck on the ??? part. I tried

def make_class(name, p, code); r = Class.new(p.split(/::/).inject(Object){|s,x|s.const_get(x)}); Object.const_set(name, r); r.module_eval code; r end

=> nil

class A; class B; end end

=> nil

klass = make_class "Foo", "A::B", "def bar; 'bar' end"

=> Foo

klass.ancestors

=> [Foo, A::B, Object, Kernel]

klass.new.bar

=> "bar"

You can later modify klass dynamically with module_eval, define_method,
etc.

···

On Sun, Aug 15, 2004 at 04:31:11AM +0900, Claus Spitzer wrote:

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Great! Thanks for the quick response. Just another quick one on that context:

Now that I have the class definition and can extend it easily, I'm
wondering how I would do

qux = Klass.new

using str1 or klass. I could do

eval "qux = #{str}.new"

and that would be fine, but it somehow seems forced. Any hints?

···

On Sun, 15 Aug 2004 04:40:41 +0900, Sam Stephenson <sstephenson@gmail.com> wrote:

On Sun, 15 Aug 2004 04:31:11 +0900, Claus Spitzer > <docboobenstein@gmail.com> wrote:
> I'm stuck on the ??? part. I tried
>
> class eval( str1 )
>
> I tried
>
> class str.intern # (I think I know by now why this one was a stupid idea)
>
> I tried
>
> $myclassref = eval str1
> class $myclassref
>
> All to no avail. So I'm wondering whether I'm trying to do this the
> wrong way. What would be the Ruby way of solving this problem?
>

> klass = eval(str1)
> klass.class_eval do
> include Mod
> end

Sam

Claus Spitzer wrote:

Great! Thanks for the quick response. Just another quick one on that context:

Now that I have the class definition and can extend it easily, I'm
wondering how I would do

qux = Klass.new

using str1 or klass. I could do

eval "qux = #{str}.new"

and that would be fine, but it somehow seems forced. Any hints?

Hmm. If I understand the question, the following should work:

   klass = eval( str )
   qux = klass.new

- Jamis

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

"I use octal until I get to 8, and then I switch to decimal."

Err... actually I just figured that out myself a minute ago :-p . I'm
not at my brightest today. Thanks for the reply though!

···

Hmm. If I understand the question, the following should work:

   klass = eval( str )
   qux = klass.new

- Jamis

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

"I use octal until I get to 8, and then I switch to decimal."