Wednesday, August 02, 2006

Quick inlining of C code in a Ruby script

A Ruby module called RubyInline allows you to do a really groovy thing: insert a small snippet of C code in your script, which is then compiled on the fly!

As an example, lets say you have the following Ruby script that calculates prime numbers (example from this blog post):

#!/usr/bin/ruby

for num in 1..10_000 do
is_prime = 1
for x in 2..(num - 1) do
if (num % x == 0)
is_prime = x
break
end
end
if is_prime == 1
puts "#{num} is a prime number"
else
puts "#{num} equals #{is_prime} * #{num/is_prime}"
end
end


You can replace a chunk of this with "inlined C" by doing something like the following:

#!/usr/bin/ruby

require "rubygems"
require "inline"

class Primes
inline do |builder|
builder.c '
int prime(int num) {
int x;
for (x = 2; x < (num - 1) ; x++) {
if (num == 2) {
return 1;
}
if (num % x == 0) {
return x;
}
}
return 1;
}'
end
end

p = Primes.new

for num in 2..10_000 do
is_prime = p.prime(num)
if is_prime == 1
puts "#{num} is a prime number"
else
puts "#{num} equals #{is_prime} * #{num/is_prime}"
end
end

Really cool. Saves having to write whole libraries/modules just to access a few C methods. I wish Java and .NET had the ability to inline small snippets of other languages if required.

Reminds me of that old geek classic "Write in C" (sung to the tune of the Beatle's song "Let it Be"):

When I find my code in tons of trouble,
Friends and colleagues come to me, Speaking words of wisdom:
"Write in C."

As the deadline fast approaches,
And bugs are all that I can see,
Somewhere, someone whispers:
"Write in C."...

1 comment:

senling said...

I got an Error when executing rubyinline program...

Info: resolving _rb_cObject by linking to __imp__rb_cObject (auto-import)
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- C:\Cygwin\bin\etc/.ruby_inline/Inline_Primes_10f1.so (LoadError)
from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from /usr/lib/ruby/gems/1.8/gems/RubyInline-3.6.5/lib/inline.rb:309:in `load'
from /usr/lib/ruby/gems/1.8/gems/RubyInline-3.6.5/lib/inline.rb:680:in `inline'
from exinlin.rb:5
>Exit code: 1