In the previous installments (
part 1 ,
part 2 ), we looked at using C to speed up or extend Ruby. Now we will learn how to use the Ruby interpreter in programs written in C / C ++.
In some applications, there is a need for an embedded language, for more fine-tuning or for writing extensions without recompilation. Ruby is very well suited for this purpose, because It has a simple and convenient API for stitching in a C / C ++ application. For example, Google SketchUp uses Ruby as a scripting language.
Let's look at how to embed Ruby into our C / C ++ applications.
Let's start by looking at the
rb_eval_string
function, which executes a string with Ruby code.
Let's look at a simple example - a program for evaluating expressions. For simplicity, we only have two variables in the expressions.
An example of the application, input:
($ a + $ b) * $ a- $ b
2
3
Result:
($ a + $ b) * $ a- $ b = 7
')
Let's see the code:
#include <ruby.h>
#include <stdio.h>
int main () {
ruby_init (); // initialization of the interpreter
int a = 0;
int b = 0;
char expr [256];
// read the expression and two variables
scanf ("% s", & expr);
scanf ("% d", & a);
scanf ("% d", & b);
// create ruby variables
VALUE r_a = INT2NUM (a);
VALUE r_b = INT2NUM (b);
// and make them available in the interpreter
rb_define_variable ("$ a", & r_a);
rb_define_variable ("$ b", & r_b);
// execute the expression and print the result
VALUE res = rb_eval_string (expr);
printf ("% s =% d \ n", expr, NUM2INT (res));
return 0;
}
Note: about the data type VALUE, macros INT2NUM, etc., and for more details about working with the Ruby C API, see part 2In this example, we read two variables from the keyboard and an expression with them. Then, based on these variables, they created global Ruby variables and, using the
rb_define_variable
method, made them available in the interpreter.
As a result, using the
rb_eval_string
method, we executed the expression and displayed its result on the screen.
Now let's move on to downloading and running scripts in Ruby.
Consider this example: we need to get a hash of a string using a custom algorithm. The script works like this, the user creates the alg.rb file and implements a hashing algorithm in it. In our program, we load a custom script, pass it a string for hashing, execute the script, and print the result.
Let's see the code:
#include <ruby.h>
#include <stdio.h>
int main () {
ruby_init (); // initialization of the interpreter
ruby_init_loadpath (); // ability to include standard libraries, for example require 'MD5'
VALUE res = rb_str_new2 ("some test string"); // our test string
rb_define_variable ("$ res", & res); // make it available to the script
rb_load_file ("alg.rb"); // load the file with the algorithm
// execute the script and print the result
ruby_exec ();
printf ("% s \ n", StringValuePtr (res));
return 0;
}
Now in the alg.rb file we can implement any hash algorithms.
For example, the number of spaces in a string (not a very good hash :)):
hash = 0
$ res.split (//). each {| c | hash + = 1 if c == ""}
$ res = hash.to_s
or the sum of all characters in hexadecimal:
hash = 0
$ res.split (//). each {| c | hash + = c [0]}
$ res = hash.to_s (16)
or md5, using the standard library:
require "md5"
$ res = MD5.hexdigest ($ res)
Now about compiling applications with embedded Ruby, for example gcc:
gcc test.c -o test -I< ruby.h> -lruby
or:
gcc test.c -o test -I< ruby.h> -lruby1.8
To compile in * nix systems, you need to put the ruby-dev package, for example:
sudo apt-get install ruby1.8-dev