Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Ruby Programming
Previous Page Home Next Page

Writing Ruby in C

One of the joys of Ruby is that you can write Ruby programs almost directly in C. That is, you can use the same methods and the same logic, but with slightly different syntax to accommodate C. For instance, here is a small, fairly boring test class written in Ruby.

class Test
  def initialize
    @arr = Array.new
  end
  def add(anObject)
    @arr.push(anObject)
  end
end

The equivalent code in C should look somewhat familiar.

#include "ruby.h"

static VALUE t_init(VALUE self) {   VALUE arr;

  arr = rb_ary_new();   rb_iv_set(self, "@arr", arr);   return self; }

static VALUE t_add(VALUE self, VALUE anObject) {   VALUE arr;

  arr = rb_iv_get(self, "@arr");   rb_ary_push(arr, anObject);   return arr; }

VALUE cTest;

void Init_Test() {   cTest = rb_define_class("Test", rb_cObject);   rb_define_method(cTest, "initialize", t_init, 0);   rb_define_method(cTest, "add", t_add, 1); }

Let's go through this example in detail, as it illustrates many of the important concepts in this chapter. First off, we need to include the header file ``ruby.h'' to obtain the necessary definitions.

Now look at the last function, Init_Test. Every class or module defines a C global function named Init_ Name. This function will be called when the interpreter first loads the extension Name (or on startup for statically linked extensions). It is used to initialize the extension and to insinuate it into the Ruby environment. In this case, we define a new class named Test, which is a subclass of Object (represented by the external symbol rb_cObject; see ``ruby.h'' for others).

Next we set up add and initialize as two instance methods for class Test. The calls to rb_define_method establish a binding between the Ruby method name and the C function that will implement it, so a call to the add method in Ruby will call the C function t_add with one argument.

Similarly, when new is called for this class, Ruby will construct a basic object and then call initialize, which we have defined here to call the C function t_init with no (Ruby) arguments.

Now go back and look at the definition of initialize. Even though we said it took no arguments, there's a parameter here! In addition to any Ruby arguments, every method is passed an initial VALUE argument that contains the receiver for this method (the equivalent of self in Ruby code).

The first thing we'll do in initialize is create a Ruby array and set the instance variable @arr to point to it. Just as you would expect if you were writing Ruby source, referencing an instance variable that doesn't exist creates it.

Finally, the function t_add gets the instance variable @arr from the current object and calls Array#push to push the passed value onto that array. When accessing instance variables in this way, the @-prefix is mandatory---otherwise the variable is created, but cannot be referenced from Ruby.

Despite the extra, clunky syntax that C imposes, you're still writing in Ruby---you can manipulate objects using all of the method calls you've come to know and love, with the added advantage of being able to craft tight, fast code when needed.

WARNING: Every C function that is callable from Ruby must return a VALUE, even if it's just Qnil. Otherwise, a core dump (or GPF) will be the likely result.

We can use the C version of the code in Ruby simply by require-ing it dynamically at runtime (on most platforms).

require "code/ext/Test"
t = Test.new
t.add("Bill Chase")
C/Ruby datatype conversion functions and macros
C Datatypes to Ruby Objects:
INT2NUM(int) -> Fixnum or Bignum
INT2FIX(int) -> Fixnum (faster)
INT2NUM(long or int) -> Fixnum or Bignum
INT2FIX(long or int) -> Fixnum (faster)
CHR2FIX(char) -> Fixnum
rb_str_new2(char *) -> String
rb_float_new(double) -> Float
Ruby Objects to C Datatypes:
int NUM2INT(Numeric) (Includes type check)
int FIX2INT(Fixnum) (Faster)
unsigned int NUM2UINT(Numeric) (Includes type check)
unsigned int FIX2UINT(Fixnum) (Includes type check)
long NUM2LONG(Numeric) (Includes type check)
long FIX2LONG(Fixnum) (Faster)
unsigned long NUM2ULONG(Numeric) (Includes type check)
char NUM2CHR(Numeric or String) (Includes type check)
char * STR2CSTR(String)
char * rb_str2cstr(String, int *length) Returns length as well
double NUM2DBL(Numeric)

Ruby Programming
Previous Page Home Next Page

 
 
  Published under the terms of the Open Publication License Design by Interspire