Writing Inline C in Your Ruby Code

Credit: Garrett Rooney

Problem

You want to implement small portions of your program in C without going to the trouble of creating a C extension to Ruby.

Solution

Embed C code right in your Ruby program, and let RubyInline (available as the rubyinline gem) create an extension automatically.

For example, if you want to use Cs stdio functions to copy a file, you can write RubyInline code like this:[1]

[1] RubyInline won work from within irb, so this is a standalone program.

	#!/usr/bin/ruby -w
	# copy.rb
	require 
ubygems
	require inline

	class Copier
	inline do |builder|
	 builder.c < 0)
	 {
	 fwrite(buffer, 1, nread, dest_f);
	 nread = fread(buffer, 1, 1024, source_f);
	 }
	}
	END
	 end
	end

The C function copy_file now exists as an instance method of Copier:

	open(source.txt, w) { |f| f << Some text. }
	Copier.new.copy_file(source.txt, dest.txt)
	puts open(dest.txt) { |f| f.read }

Run this Ruby script, and youll see it copy the string "Some text." from source.txt to dest.txt.

Discussion

RubyInline is a framework that lets you embed other languages inside your Ruby code. It defines the Module# inline method, which returns a builder object. You pass the builder a string containing code written in a language other than Ruby, and the builder transforms it into something that you can call from Ruby.

When given C or C++ code (the two languages supported in the default RubyInline install), the builder objects writes a small extension to disk, compiles it, and loads it. You don have to deal with the compilation yourself, but you can see the generated code and compiled extensions in the .ruby_inline subdirectory of your home directory.

There are some limitations you should be aware of, though.

First, RubyInline only understands a limited subset of C and C++. The functions you embed can only accept and return arguments of the types char, unsigned, unsigned int, char *, int, long, and unsigned long.

If you need to use other types, RubyInline won be able to automatically generate the wrapper functions. Youll have to work around the problem using the inline.c_raw function to embed code that conforms to the Ruby C API, just like any other extension.

Second, if you e going to just run a script that uses RubyInline, youll need to have the Ruby development libraries and headers installed, along with a C/C++ compiler to actually build the extension.

Theres a way around this, though: RubyInline lets you generate a RubyGem package with a precompiled extension. See the RubyInline docs on the inline_package script for details.

As always, be careful to make sure that its actually worth the trouble to write C code. You should only rewrite part of a Ruby program in C if youve actually determined that Ruby spends a lot of time there. You should benchmark before and after your change, to make sure that you e making things better rather than worse. Writing C code within your Ruby code is much easier than writing a separate extension, but writing Ruby code is easier still.

See Also

  • http://www.zenspider.com/ZSS/Products/RubyInline/
  • http://rubyforge.org/projects/rubyinline/
  • Recipe 17.12, "Profiling Your Application"
  • Recipe 17.13, "Benchmarking Competing Solutions"


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net