Slide 1

Slide 1 text

EXTENDING RUBY Raúl Naveiras @rnaveiras

Slide 2

Slide 2 text

require 'rubygems' require 'delorean' Delorean.time_travel_to("8 years ago")

Slide 3

Slide 3 text

PICKAXE 1ST EDITION 2000 2ND EDITION 2004

Slide 4

Slide 4 text

http://www.flickr.com/photos/mrbill/2482009942/in/set-72157604987885136/

Slide 5

Slide 5 text

ANATOMY OF AN EXTENSION IN C

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

WAT!!

Slide 8

Slide 8 text

// filename madridrb.c #include ; static int id_push; static VALUE t_init(VALUE self) { VALUE people; people = rb_ary_new(); rb_iv_set(self, "@people", people); return self; } static VALUE t_add(VALUE self, VALUE obj) { VALUE people; people = rb_iv_get(self, "@people"); rb_funcall(people, id_push, 1, obj); return people; } VALUE cMadridrb; void Init_madridrb() { cMadridrb = rb_define_class("Madridrb", rb_cObject); rb_define_method(cMadridrb, "initialize", t_init, 0); rb_define_method(cMadridrb, "add", t_add, 1); id_push = rb_intern("push"); }

Slide 9

Slide 9 text

# filename extconf.rb require 'mkmf' dir_config('madridrb') create_makefile('madridrb')

Slide 10

Slide 10 text

# filename extconf.rb require 'mkmf' dir_config('madridrb') create_makefile('madridrb')

Slide 11

Slide 11 text

class Madridrb def initialize @people = [] end def add(person) @people << person end end # filename extconf.rb require 'mkmf' dir_config('madridrb') create_makefile('madridrb')

Slide 12

Slide 12 text

ESSENTIALLY A SCAM

Slide 13

Slide 13 text

RUBY OBJECTS IN C EVERYTHING IN RUBY IS AN OBJECT

Slide 14

Slide 14 text

RUBY OBJECTS IN C EVERYTHING IN RUBY IS AN OBJECT WHEN WRITING RUBY IN C, EVERYTHING IS A VALUE

Slide 15

Slide 15 text

CHECK THE DATA TYPE OF ‘VALUE’ 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; } Check_Type(str, T_STRING); FIXNUM_P(value); // fixnum? NIL_P(value); // nil?

Slide 16

Slide 16 text

T_NIL T_OBJECT T_CLASS T_MODULE T_FLOAT! T_STRING T_REGEXP T_ARRAY! T_HASH! ! T_STRUCT! T_BIGNUM! T_FIXNUM! T_COMPLEX T_RATIONAL T_FILE! ! T_TRUE! ! T_FALSE T_DATA T_SYMBOL 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 IO true false data symbol CHECK THE DATA TYPE OF ‘VALUE’

Slide 17

Slide 17 text

CHECK THE DATA TYPE OF THE ‘VALUE’ #include ; static VALUE print_string(VALUE self, VALUE string) { Check_Type(string, T_STRING); printf("%s", RSTRING(string)->ptr); return Qnil; }

Slide 18

Slide 18 text

DO NOT USE ‘RUBY DATA’ DIRECTLY

Slide 19

Slide 19 text

CONVERT A VALUE INTO C DATA // converts any Ruby numbers into C integers int NUM2INT(Numeric); int FIX2INT(Fixnum); unsigned int NUM2UINT(Numeric); unsigned int FIX2UINT(Fixnum); long NUM2LONG(Number); long FIX2LONG(Fixnum); double NUM2DBL(Numeric); // convert any Ruby strings into C char* char NUM2ULONG(Numeric_or_String); char* StringValue(str); char* StringValuePtr(str); char* StringValueCStr(str); // for other objects RSTRING_LEN(obj); // length of the Ruby string RSTRING_PTR(obj); // pointer to string storage VALUE array; RARRAY(array)->len; // length of the Ruby array RARRAY_LEN RARRAY(array)->capa; // capacity of the Ruby array RARRAY(array)->ptr; // pointer to array storage RARRAY_PTR // There are similar accessors for hashes (RHASH), files (RFILE) and so on.

Slide 20

Slide 20 text

CONVERT C DATA INTO A VALUE // convert C numbers to Ruby values INT2FIX(); // for integers within 31bits. INT2NUM(); // for arbitrary sized integer.

Slide 21

Slide 21 text

CONVERT C DATA INTO A VALUE // convert C numbers to Ruby values INT2FIX(); // for integers within 31bits. INT2NUM(); // for arbitrary sized integer. int version = 100; static VALUE madridrb_version(VALUE self) { return INT2NUM(version); }

Slide 22

Slide 22 text

MANIPULATING ‘RUBY DATA’ USING THE API

Slide 23

Slide 23 text

STRINGS rb_str_new(const char *ptr, long len); // Creates a new Ruby string. rb_str_new2(const char *ptr); // Creates a new Ruby string from a C string. rb_str_new_cstr(const char *ptr); // This is equivalent to rb_str_new(ptr, strlen(ptr)). rb_sprintf(const char *format, ...); rb_vsprintf(const char *format, va_list ap); rb_str_cat(VALUE str, const char *ptr, long len); rb_str_cat2(VALUE str, const char* ptr); rb_str_catf(VALUE str, const char* format, ...); rb_str_vcatf(VALUE str, const char* format, va_list ap); rb_enc_str_new(const char *ptr, long len, rb_encoding *enc); rb_usascii_str_new(const char *ptr, long len); rb_usascii_str_new_cstr(const char *ptr); rb_str_resize(VALUE str, long len); rb_str_set_len(VALUE str, long len);

Slide 24

Slide 24 text

ARRAYS // Array functions rb_ary_new(); rb_ary_new2(long len); rb_ary_new3(long n, ...); rb_ary_new4(long n, VALUE *elts); //Creates an n-element array from a C array. rb_ary_to_ary(VALUE obj); rb_ary_aref(argc, VALUE *argv, VALUE ary); rb_ary_entry(VALUE ary, long offset); // ary[offset] rb_ary_subseq(VALUE ary, long beg, long len); // ary[beg,len] rb_ary_push(VALUE ary, VALUE val); rb_ary_pop(VALUE ary); rb_ary_shift(VALUE ary); rb_ary_unshift(VALUE ary, VALUE val); rb_ary_cat(VALUE ary, const VALUE *ptr, long len);

Slide 25

Slide 25 text

ADDING FEATURES TO RUBY

Slide 26

Slide 26 text

MODULES, CLASSES, METHODS... VALUE rb_define_module(const char *name); VALUE rb_define_class(const char *name, VALUE super); VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super); VALUE rb_define_module_under(VALUE outer, const char *name); void rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc); void rb_define_singleton_method(VALUE object, const char *name, VALUE (*func)(), int argc); void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc); void rb_define_protected_method(VALUE klass, const char *name, VALUE (*func)(), int argc); void rb_define_const(VALUE klass, const char *name, VALUE val); void rb_define_global_const(const char *name, VALUE val); void rb_include_module(VALUE klass, VALUE val); void rb_extend_object(VALUE object, VALUE val);

Slide 27

Slide 27 text

INVOKING RUBY METHODS FROM C VALUE rb_funcall(VALUE recv, ID mid, int nargc, ...); VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv);

Slide 28

Slide 28 text

ACCESSING RUBY VARIABLES AND CONSTANTS VALUE rb_ivar_get(VALUE obj, ID id); VALUE rb_ivar_set(VALUE obj, ID id, VALUE val); VALUE rb_const_get(VALUE obj, ID id);

Slide 29

Slide 29 text

// filename madridrb.c #include ; static int id_push; static VALUE t_init(VALUE self) { VALUE people; people = rb_ary_new(); rb_iv_set(self, "@people", people); return self; } static VALUE t_add(VALUE self, VALUE obj) { VALUE people; people = rb_iv_get(self, "@people"); rb_funcall(people, id_push, 1, obj); return people; } VALUE cMadridrb; void Init_madridrb() { cMadridrb = rb_define_class("Madridrb", rb_cObject); rb_define_method(cMadridrb, "initialize", t_init, 0); rb_define_method(cMadridrb, "add", t_add, 1); id_push = rb_intern("push"); }

Slide 30

Slide 30 text

ALLOCATING FUNCTIONS #include ; static VALUE rb_alloc(VALUE klass) { VALUE obj; // malloc and other stuff obj = Data_Wrap_Struct(klass, .....) return obj; } VALUE cMadridrb; static Init_madridrb(VALUE self, VALUE wadus) { cMadridrb = rb_define_class("Madridrb", rb_cObject); rb_define_alloc_func(cMadridrb, rb_alloc); // ... }

Slide 31

Slide 31 text

DEMO

Slide 32

Slide 32 text

REFERENCES • README.EXT • guides.rubygems.org/c-extensions/ • Ruby Hacking Guide - http://i.loveruby.net/ja/rhg/book/

Slide 33

Slide 33 text

REFERENCES

Slide 34

Slide 34 text

require 'rubygems' require 'delorean' Delorean.back_to_the_present

Slide 35

Slide 35 text

OTHER OPTIONS

Slide 36

Slide 36 text

OTHER OPTIONS • SWING

Slide 37

Slide 37 text

OTHER OPTIONS • SWING • Rb++

Slide 38

Slide 38 text

OTHER OPTIONS • SWING • Rb++ • Ruby FFI

Slide 39

Slide 39 text

• DOESN’T NEED COMPILATION RUBY FFI

Slide 40

Slide 40 text

• DOESN’T NEED COMPILATION • MULTI-PLATFORM RUBY FFI

Slide 41

Slide 41 text

• DOESN’T NEED COMPILATION • MULTI-PLATFORM • MULTI-IMPLEMENTATION RUBY FFI

Slide 42

Slide 42 text

• DOESN’T NEED COMPILATION • MULTI-PLATFORM • MULTI-IMPLEMENTATION • THE CODE IS RUBY. EASY TO READ AND EASY TO WRITE RUBY FFI

Slide 43

Slide 43 text

RUBY FFI

Slide 44

Slide 44 text

RUBY FFI

Slide 45

Slide 45 text

module Fibonacci extend FFI::Library ffi_lib './fibonacci.so' attach_function :rfibonnaci, [:int], :int attach_function :ifibonnaci, [:int], :int end

Slide 46

Slide 46 text

module Fibonacci extend FFI::Library ffi_lib './fibonacci.so' attach_function :rfibonnaci, [:int], :int attach_function :ifibonnaci, [:int], :int end require 'ffi' require 'fibonacci' puts Fibonacci.rfibonnaci 10 puts Fibonacci.ifibonnaci 40

Slide 47

Slide 47 text

NOT KIDDING

Slide 48

Slide 48 text

THANKS!!! github.com/rnaveiras twitter.com/rnaveiras speakerdeck.com/u/rnaveiras