This document explains how to make extension libraries for Ruby.
In C, variables have types and data do not have types. In contrast, Ruby variables do not have a static type, and data themselves have types, so data will need to be converted between the languages.
Data in Ruby are represented by the C type `VALUE'. Each VALUE data has its data type.
To retrieve C data from a VALUE, you need to:
Identify the VALUE's data type
Convert the VALUE into C data
Converting to the wrong data type may cause serious problems.
Data Types¶ ↑The Ruby interpreter has the following data types:
nil
ordinary object
class
module
floating point number
string
regular expression
array
associative array
(Ruby) structure
multi precision integer
Fixnum(31bit or 63bit integer)
complex number
rational number
true
false
data
symbol
In addition, there are several other types used internally:
included module
MatchData object
undefined
syntax tree node
object awaiting finalization
Most of the types are represented by C structures.
Data Type of the VALUE¶ ↑The macro TYPE() defined in ruby.h shows the data type of the VALUE. TYPE() returns the constant number T_XXXX described above. To handle data types, your code will look something like this:
switch (TYPE(obj)) {
case T_FIXNUM:
/* process Fixnum */
break;
case T_STRING:
/* process String */
break;
case T_ARRAY:
/* process Array */
break;
default:
/* raise exception */
rb_raise(rb_eTypeError, "not valid value");
break;
}
There is the data type check function
void Check_Type(VALUE value, int type)
which raises an exception if the VALUE does not have the type specified.
There are also faster check macros for fixnums and nil.
FIXNUM_P(obj) NIL_P(obj)
Data¶ ↑The data for type T_NIL, T_FALSE, T_TRUE are nil, false, true respectively. They are singletons for the data type. The equivalent C constants are: Qnil, Qfalse, Qtrue. Note that Qfalse is false in C also (i.e. 0), but not Qnil.
The T_FIXNUM data is a 31bit or 63bit length fixed integer. This size depends on the size of long: if long is 32bit then T_FIXNUM is 31bit, if long is 64bit then T_FIXNUM is 63bit. T_FIXNUM can be converted to a C integer by using the FIX2INT() macro or FIX2LONG(). Though you have to check that the data is really FIXNUM before using them, they are faster. FIX2LONG() never raises exceptions, but FIX2INT() raises RangeError if the result is bigger or smaller than the size of int. There are also NUM2INT() and NUM2LONG() which converts any Ruby numbers into C integers. These macros include a type check, so an exception will be raised if the conversion failed. NUM2DBL() can be used to retrieve the double float value in the same way.
You can use the macros StringValue() and StringValuePtr() to get a char* from a VALUE. StringValue(var) replaces var's value with the result of “var.to_str()”. StringValuePtr(var) does the same replacement and returns the char* representation of var. These macros will skip the replacement if var is a String. Notice that the macros take only the lvalue as their argument, to change the value of var in place.
You can also use the macro named StringValueCStr(). This is just like StringValuePtr(), but always adds a NUL character at the end of the result. If the result contains a NUL character, this macro causes the ArgumentError exception. StringValuePtr() doesn't guarantee the existence of a NUL at the end of the result, and the result may contain NUL.
Other data types have corresponding C structures, e.g. struct RArray for T_ARRAY etc. The VALUE of the type which has the corresponding structure can be cast to retrieve the pointer to the struct. The casting macro will be of the form RXXXX for each data type; for instance, RARRAY(obj). See “ruby.h”. However, we do not recommend to access RXXXX data directly because these data structures are complex. Use corresponding rb_xxx() functions to access the internal struct. For example, to access an entry of array, use rb_ary_entry(ary, offset) and rb_ary_store(ary, offset, obj).
There are some accessing macros for structure members, for example `RSTRING_LEN(str)' to get the size of the Ruby String object. The allocated region can be accessed by `RSTRING_PTR(str)'.
Notice: Do not change the value of the structure directly, unless you are responsible for the result. This ends up being the cause of interesting bugs.
Data into VALUE¶ ↑To convert C data to Ruby values:
left shift 1 bit, and turn on its least significant bit (LSB).
cast to VALUE.
You can determine whether a VALUE is a pointer or not by checking its LSB.