Calling Ruby from Delphi


#1

I want to call an embedded ruby function from Delphi 2009. A C or C++
example is also ok. For example on the Ruby side:

def myFunction(a,b,c)
rv1=ab -c
rv2=a2 + b2
rv3=b
c
return rv1, rv2, rv3
end

The above function is just some non-sense, but hopefully easy to use as
an example. MyExample.rb contains the above script.

On the Delphi side:

Starting with:

fState := 0;
ruby_init;
ruby_init_loadpath;
rb_set_safe_level(0);
ruby_script(‘embedded’); // or should it be ruby_script(‘ruby’)

Ok now I have no clue as to what top do next. Somehow MyExample.rb must
be loaded.

Maybe:
rb_load_file(‘MyExample.rb’) ???

Next call myFunction(a,b,c) ???

I found rb_funcall2 and VALUE is defined as: typedef unsigned long
VALUE
However I do not have documentation that explains the meaning of recv or
how to get the parameter for recv.

VALUE rb_funcall2(VALUE recv,
ID mid,
int argc,
const VALUE * argv
)

Any help or suggestions are appreciated.


#2

You can connect Delphi Prism (Chrome/Oxgene) or C# or some other .NET
language with the Ruby interpreter using our free component, The Ruby
Connector. I haven’t used Delphi 2009 (does that still have a .NET
version?) so can’t comment specifically on that. The Ruby Connector
comes with a comprehensive manual and lots of sample code…

http://www.sapphiresteel.com/SapphireSteel-Downloads

best wishes
Huw C.

SapphireSteel Software
http://www.sapphiresteel.com


#3

Rob Ram wrote:

The above function is just some non-sense, but hopefully easy to use as
ruby_script(‘embedded’); // or should it be ruby_script(‘ruby’)
I found rb_funcall2 and VALUE is defined as: typedef unsigned long
)

Any help or suggestions are appreciated.

Hi Rob,

This is some of the stuff that I use in a Borland C++ Builder
application - not sure if it helps you. The sequence is exaqctly the
same as what the online version of PickAxe recommends, if I remember
correctly.

/* Initialize the Ruby VM */
void rubyVM_initialize()
{
ruby_init();
ruby_init_loadpath();
ruby_script(“embedded”); //set a name that the script will use
return;
}

/* Finalize the Ruby VM */
void rubyVM_finalize()
{
ruby_finalize();
}

/* Functions to call the functions in Ruby script */
static VALUE wrap_sum(VALUE args) {
VALUE *values = (VALUE *)args;
VALUE summer = values[0];
VALUE max = values[1];
//object, function, count?, argument
return rb_funcall(summer, id_sum, 1, max);
}

static VALUE protected_sum(VALUE summer, VALUE max) {
int error;
VALUE args[2];
VALUE result;
args[0] = summer;
args[1] = max;
result = rb_protect(wrap_sum, (VALUE)args, &error);
return error ? Qnil : result;
}

/* Sample script execution */
int run_a_script(void)
{
int value;
int *next = Values;
char output[200];

/* Call ruby VM init first */
rubyVM_initialize();
rb_require (“sum.rb”); //script that you want to use

/* Instantiate the class (Summer) you want to use */
VALUE summer = rb_class_new_instance(0, 0,
rb_const_get(rb_cObject, rb_intern(“Summer”)));

/* Access the function in that class /
/
Note id_sum is a global variable below */
id_sum = rb_intern(“sum”); //the function

while (value = next++) {
/
The next line does the hard work through 2 functions */
VALUE result = protected_sum(summer, INT2NUM(value));
if (NIL_P(result))
{
sprintf(output,“Sum to %d doesn’t compute!\n”, value);
}
else
{
sprintf(output,“Sum to %d is %d\n”, value, NUM2INT(result));
}
//MessageBox(NULL,output,“Ruby result!”,MB_OK);

}

//rubyVM_finalize();
//return;
}

I’m sorry I’m in a bit of a rush, but do ask again - I’ll reply with
more details if this doesn’t help. Essentially, I think what you need
is:

  • rb_require (“sum.rb”); //script that you want to use
  • VALUE result = protected_sum(summer, INT2NUM(value));
  • See the wrapped functions to pack the parameters and safely call the
    function
  • rb_funcall(summer, id_sum, 1, max); // I think this is object,
    function_number, # of parameters, max

Hopefully this will help:
http://whytheluckystiff.net/ruby/pickaxe/html/ext_ruby.html

Cheers
Mohit.


#4

Mohit S. wrote:

This is some of the stuff that I use in a Borland C++ Builder
application - not sure if it helps you. The sequence is exaqctly the
same as what the online version of PickAxe recommends, if I remember
correctly.

Hi Mohit,
I will give it a try.
Thank You


#5

Huw C. wrote:

You can connect Delphi Prism (Chrome/Oxgene) or C# or some other .NET
language with the Ruby interpreter using our free component, The Ruby
Connector. I haven’t used Delphi 2009 (does that still have a .NET
version?) so can’t comment specifically on that. The Ruby Connector
comes with a comprehensive manual and lots of sample code…

http://www.sapphiresteel.com/SapphireSteel-Downloads

best wishes
Huw C.

SapphireSteel Software
http://www.sapphiresteel.com

Thank you for your reply.

I was successful calling Ruby from Delphi 2009. I used the Delphi API
found at: http://sourcepole.ch/2006/9/1/embedding-ruby-in-kylix-delphi .
This was originally written for Delphi 2006. However it will work with
Delphi 2009 with minor modifications. Delphi 2009 now supports Unicode
strings and user code strings must be re-cast to
ansiString/pAnsiString/ansiChar/pAnsiChar to be compatible with Ruby
strings.
Delphi 2009 is intended for native Windows development. There are other
versions of Delphi available for .net support.

The source code, “rubycomp-0.8-src.tar.gz”, provides a Delphi component
for easy evaluation. In my case however, I did not want to re-direct the
IO and removed the Ruby component. Otherwise, Ruby access is through
msvcrt-ruby18.dll. The source code provides Delphi files to access the
Ruby DLL. It’s basically ruby.h and other c++ files re-written for
Delphi.

To call Ruby functions from Delphi (in simplified terms):

  1. First initialize Ruby.

  2. Then use rb_require function to load the Ruby file.

  3. Calling the “rb_eval_string” can easily access any function within
    the Ruby file. For example:
    rv := rb_eval_string(‘myFunction(a,b,c)’); // From the prior example.

  4. Finally evaluate rv using:
    rtn := dl_Variant(rv); // where rtn is a variant array.

// multi-results from the prior example.
rv1 := rtn[0];
rv2 := rtn[1];
rv3 := rtn[2];

The dl_Variant function is found in uConv.pas (extracted from
rubycomp-0.8-src.tar.gz).

There may be better methods to call a Ruby function from Delphi, but
this does seem to work efficiently.


#6

Mohit S. wrote:

Rob Ram wrote:

I want to call an embedded ruby function from Delphi 2009. A C or C++
example is also ok. For example on the Ruby side:

Hi Rob,

This is some of the stuff that I use in a Borland C++ Builder
application - not sure if it helps you. The sequence is exaqctly the
same as what the online version of PickAxe recommends, if I remember
correctly.

Rob, any luck with this?

Cheers,
Mohit.
1/7/2009 | 9:15 AM.


#7

Mohit S. wrote:

Mohit S. wrote:

Rob Ram wrote:

I want to call an embedded ruby function from Delphi 2009. A C or C++
example is also ok. For example on the Ruby side:

Hi Rob,

This is some of the stuff that I use in a Borland C++ Builder
application - not sure if it helps you. The sequence is exaqctly the
same as what the online version of PickAxe recommends, if I remember
correctly.

Rob, any luck with this?

Cheers,
Mohit.
1/7/2009 | 9:15 AM.

I haven’t had a chance to work on it yet; hopefully I will soon.
Thanks for your interest.
Rob