📜 ⬆️ ⬇️

Ruby and C. Part 3.

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 2

In 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

Source: https://habr.com/ru/post/50039/


All Articles