From: Stefano Crocco Date: 2008-03-27T17:25:16+09:00 Subject: Re: embedding ruby (*not* extending) On Thursday 27 March 2008, John Smith wrote: > I need to embed a scripting languange in a C++ application. > > Currently I am evaluating some scripting languages for this purpose. > > * perl (that works, although it needs a big amount of C++ glue code > to deal with the perl stack(s) > * python - have not tried yet > * lua - that's really great, very easy to embed. Not surpring since > lua is "designed to be embedded". Unfortuneately the lua interpreter is > very limited > * ruby - there is no/very limited docs about howto do that > > > to clarify: I am not talking about *extending* ruby, e.g. via SWIG. That > is quite easy to do. > > What I mean is *embedding* it into an existing large C++ program and > than call some ruby functions (and to give some values to this ruby > functions and to get some values back from this ruby functions) > > As it is in the following lua example: > > int main (void) { > lua_State *L = lua_open(); > > /* load and parse script - but do not execute */ > luaL_loadfile(L, "example.lua"); > > /* push functions and arguments */ > lua_getglobal(L, "f"); /* function to be called */ > lua_pushnumber(L, x); /* push 1st argument */ > lua_pushnumber(L, y); /* push 2nd argument */ > > /* do the call (2 arguments, 1 result) */ > lua_pcall(L, 2, 1, 0); > > /* retrieve result */ > int result = lua_tonumber(L, -1); > lua_pop(L, 1); > > lua_close(L); > return 0; > } > > > > I have found some docs a la: > > int main(int argc, char **argv) > { > RUBY_INIT_STACK > ruby_init(); > ruby_options(argc, argv); > ruby_run(); > return(0); > } > > But I did not find a simple example describing howto bring values onto > the ruby stack, call a function and get results back. Moreover I found > out that ruby_run() does not return. I need to have the C++ application > keeping control. Embedding ruby is not too difficult, even if, as you noticed, there isn't much documentation. Essential documentation is the Ruby C API, which you can find at http://www.ruby-doc.org/doxygen/1.8.4/index.html (look expecially at the Global page). Unfortunately, it only lists functions and structures, but doesn't explain them. A little explanation of the most useful functions is given in the chapter "Extending ruby" of the pickaxe. As first thing, you should remove ruby_run, since it works more or less like Kernel#exec, which is not what you want. To load a file (notice that you can't load but not execute a file in ruby) you can use rb_require or rb_f_load, which work exactly like require and load in ruby. Calling a method is conceptually easy: you simply use the rb_funcall function, passing it the receiver of the method, an int corresponding to the name of the method (usually obtained using the rb_intern function), the number of arguments, and the arguments themselves. The tricky part is to obtain the receiver of the method. If the method is a global method, you can obtain the receiver with: VALUE rec = rb_eval("main"); You can create an instance of a class with the following code: rb_funcall(rb_const_get(rb_mKernel, rb_intern("Cls")), rb_intern("new"), n_args, arg1, arg2,...); where n_args is the number of arguments you pass and arg1, arg2 and so on are the actual arguments. On this mailing list, I recently saw mentioned a project, called "rice" which should be a C++ interface to the ruby C API. I never used it, but you may find it useful. It's at http://rubyforge.org/projects/rice. I hope this helps Stefano