Since the introduction of the RubyVM module in the Core API, Ruby developers have been able to get an insight into the internal workings of Ruby. The official Ruby documentation has a detailed explanation about the capabilities of this module if you’re into it. In this post, I will be discussing about how we can utilize this module to compile Ruby code to binary and load it back into another binding for execution at a later time.

Do not use the methods discussed below in your production environments.

Creating a sample program for compilation

Let us begin by creating a simple Ruby program that we can compile to binary. Here, I’ve just created a fibonacci.rb file containing the ruby implementation of the ever so famous fibonacci series algorithm.

# fibonacci.rb PHI = (1+Math.sqrt(5))/2 def fibonacci(n) ((PHI ** n) - ((-PHI) ** -n)) / Math.sqrt(5) end fibonacci(100)

Designing a Ruby “Compiler” in Ruby.

Now we will create a compiler file compiler.rb which will help us compile the fibonacci.rb file we created in the first step to binary. We will be using this file to convert our ruby code to binary which can be stored and put away in a file.

# compiler.rb source_code = File.open(ARGV[0], 'r') # load the file from arguments compiled_code = RubyVM::InstructionSequence.compile(source_code) binary_code = compiled_code.to_binary binary_file = File.open(ARGV[0].split('.').first + '.bin', 'w+') binary_file.puts binary_code binary_file.close

You can run the compiler to compile fibonacci.rb as follows:

$ ruby compiler.rb fibonacci.rb

After running the above command, the directory containing the fibonacci.rb file will also contain a binary file named fibonacci.bin. This file contains all our ruby code compiled to binary.

Execution Of The Compiled Binary Code

Now that we have the binary code of our sample program, we will create another ruby program to load the binary code and execute it in a separate binding. To achieve this, we shall create a new file called exec.rb and add the following code to it:

exec.rb executable_binary_code = File.open(ARGV[0], 'r').readlines.join('') compiled_instruction_sequence = RubyVM::InstructionSequence.load_from_binary(executable_binary_code) compiled_instruction_sequence.eval

We will use the exec.rb file to execute our binary code as follows:

$ ruby exec.rb fibonacci.bin

And voila! There you go. The program successfully executes and prints the output on the screen. That’s how you compile Ruby code to binary and execute it.

This is a simple demonstration of a very powerful feature that has plenty of applications in real world development. Right tools in the right hands can work wonders.

Cheers 🍻