Calling method defined in ruby script from external world

How can we make C routine call a "method" defined in a ruby script ?
I am familiar with extending ruby to call C routines with/without swig.
But I was not able to find a easy solution for it. The only way it may
workout is spawning the script in a different process/thread from C code and
then make it do all query/answer sequence by calling a C routine. Is there a
easy way out?
Can't we make a C routine call a specific method in a Ruby Script.

Can we access a C stack from Ruby or vice versa while debugging the Ruby
extension.

Regards,
Saumzy.

There's some discussion of this on pp 302-303 of the 2nd ed. of the Pickaxe.

The basic idea is to do the following in your C code.

1) include "ruby.h"
2) initialize ruby with:
       ruby_init()
       ruby_init_load_path()
       ruby_script("embedded")
This last sets up the name of a pseudo script file (and $0), and can
be whatever you want.

3) include whatever ruby code you need with rb_require, and/or rb_load_file

4) do what you want using the Ruby C language API. If at this point
you called ruby_run() you would be handing control over to the ruby
interpreter, which would never return. In your case you don't want to
do that.

5) before you exit your C program call rb_finalize() to clean up the
ruby runtime environment.

···

On 9/5/06, Saumya Dikshit <saumzyster@gmail.com> wrote:

How can we make C routine call a "method" defined in a ruby script ?
I am familiar with extending ruby to call C routines with/without swig.
But I was not able to find a easy solution for it. The only way it may
workout is spawning the script in a different process/thread from C code and
then make it do all query/answer sequence by calling a C routine. Is there a
easy way out?
Can't we make a C routine call a specific method in a Ruby Script.

Can we access a C stack from Ruby or vice versa while debugging the Ruby
extension.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/

Just to clarify, "rb_load_file" and "ruby_run" will execute the ruby script.
But incase, there are more than one singleon methods defined in the script
and I want to call only one of them.

If I have a "test.rb"

def good
  puts 'I am gud'
end

def bad
  puts 'I am bad'
end

I want to include one of these methods from C code.
Since executing a script in this case will simply
Do nothing as I have defined singletons here.
How do I acheve It.

Saumya.

···

On 9/5/06, Rick DeNatale <rick.denatale@gmail.com> wrote:

On 9/5/06, Saumya Dikshit <saumzyster@gmail.com> wrote:
> How can we make C routine call a "method" defined in a ruby script ?
> I am familiar with extending ruby to call C routines with/without swig.
> But I was not able to find a easy solution for it. The only way it may
> workout is spawning the script in a different process/thread from C code
and
> then make it do all query/answer sequence by calling a C routine. Is
there a
> easy way out?
> Can't we make a C routine call a specific method in a Ruby Script.
>
> Can we access a C stack from Ruby or vice versa while debugging the
Ruby
> extension.

There's some discussion of this on pp 302-303 of the 2nd ed. of the
Pickaxe.

The basic idea is to do the following in your C code.

1) include "ruby.h"
2) initialize ruby with:
       ruby_init()
       ruby_init_load_path()
       ruby_script("embedded")
This last sets up the name of a pseudo script file (and $0), and can
be whatever you want.

3) include whatever ruby code you need with rb_require, and/or
rb_load_file

4) do what you want using the Ruby C language API. If at this point
you called ruby_run() you would be handing control over to the ruby
interpreter, which would never return. In your case you don't want to
do that.

5) before you exit your C program call rb_finalize() to clean up the
ruby runtime environment.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/

I beleive that this will work, none of this actually tested.

First, they're not singleton methods, methods defined at the top level
are private instance methods of class Object. So you need to have a
receiver, but any object will do, say nil. As far as I can tell the
rb_funcall function doesn't check whether or not a method is private,
but this might change in future versions of ruby.

So something like this might work to call the good method.

     rb_funcall(Qnil, rb_intern("good"), 0)

if you instead made these class methods of a class:

class TestClass
    def TestClass.good
           puts 'I am gud'
     end

     def TestClass.bad
           puts 'I am bad'
     end
end

Then in your C code you could do something like this (again untested):

     VALUE test_class = rb_const_get(rb_cObject, rb_intern("TestClass"));
      rb_funcall(test_class, rb_intern("good"), 0, 0)

The last two arguments to rb_funcall are the number of arguments and
an array of the VALUEs of the arguments, since the count is 0 we can
use 0 for the array.

And if you made the methods instance methods:

class TestClass
    def good
           puts 'I am gud'
     end

     def bad
           puts 'I am bad'
     end
end

Then your C code might look something like this (once again untested):

     VALUE test_class = rb_const_get(rb_cObject, rb_intern("TestClass"));
     VALUE test_instance = rb_class_new_instance(0,0,test_class)
      rb_funcall(test_instance, rb_intern("good"), 0, 0)

similarly here, the first two arguments of rb_class_new_instance are
the argument count and argument array for the initialize method.

···

On 9/6/06, Saumya Dikshit <saumzyster@gmail.com> wrote:

Just to clarify, "rb_load_file" and "ruby_run" will execute the ruby script.
But incase, there are more than one singleon methods defined in the script
and I want to call only one of them.

If I have a "test.rb"

def good
  puts 'I am gud'
end

def bad
  puts 'I am bad'
end

I want to include one of these methods from C code.
Since executing a script in this case will simply
Do nothing as I have defined singletons here.
How do I acheve It.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Thanks a bundle.
Tested Successfully.

Saumya.

···

On 9/6/06, Rick DeNatale <rick.denatale@gmail.com> wrote:

On 9/6/06, Saumya Dikshit <saumzyster@gmail.com> wrote:
> Just to clarify, "rb_load_file" and "ruby_run" will execute the ruby
script.
> But incase, there are more than one singleon methods defined in the
script
> and I want to call only one of them.
>
> If I have a "test.rb"
>
> def good
> puts 'I am gud'
> end
>
> def bad
> puts 'I am bad'
> end

> I want to include one of these methods from C code.
> Since executing a script in this case will simply
> Do nothing as I have defined singletons here.
> How do I acheve It.

I beleive that this will work, none of this actually tested.

First, they're not singleton methods, methods defined at the top level
are private instance methods of class Object. So you need to have a
receiver, but any object will do, say nil. As far as I can tell the
rb_funcall function doesn't check whether or not a method is private,
but this might change in future versions of ruby.

So something like this might work to call the good method.

     rb_funcall(Qnil, rb_intern("good"), 0)

if you instead made these class methods of a class:

class TestClass
    def TestClass.good
           puts 'I am gud'
     end

     def TestClass.bad
           puts 'I am bad'
     end
end

Then in your C code you could do something like this (again untested):

     VALUE test_class = rb_const_get(rb_cObject, rb_intern("TestClass"));
      rb_funcall(test_class, rb_intern("good"), 0, 0)

The last two arguments to rb_funcall are the number of arguments and
an array of the VALUEs of the arguments, since the count is 0 we can
use 0 for the array.

And if you made the methods instance methods:

class TestClass
    def good
           puts 'I am gud'
     end

     def bad
           puts 'I am bad'
     end
end

Then your C code might look something like this (once again untested):

     VALUE test_class = rb_const_get(rb_cObject, rb_intern("TestClass"));
     VALUE test_instance = rb_class_new_instance(0,0,test_class)
      rb_funcall(test_instance, rb_intern("good"), 0, 0)

similarly here, the first two arguments of rb_class_new_instance are
the argument count and argument array for the initialize method.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/