Last active
December 14, 2015 03:19
-
-
Save johnbellone/5020125 to your computer and use it in GitHub Desktop.
Marrying Ruby and C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// $ gcc -I$HOME/.rvm/rubies/ruby-1.9.3-p374/include/ruby-1.9.1 \ | |
// > -L$HOME/.rvm/rubies/ruby-1.9.3-p374/lib -lruby-static \ | |
// > -DHAVE_STRUCT_TIMESPEC -std=c99 main.c | |
#include <ruby.h> | |
#include <stdio.h> | |
// Any errors are going to be stored in the global variable $!. So | |
// if we want to print this out we need to $!.to_s. | |
static void print_exception() { | |
VALUE ex = rb_gv_get("$!"); | |
puts(RSTRING_PTR(rb_obj_as_string(ex))); | |
} | |
// Bar#initialize | |
static VALUE rb_bar_initialize(VALUE self) { | |
// Set the instance variable @postfix to 'world'. | |
rb_iv_set(self, "@postfix", rb_str_new2("world")); | |
return self; | |
} | |
// Bar#say | |
static VALUE rb_bar_say(VALUE self, VALUE message) { | |
// If the message is nil (or the object isn't a String) then we | |
// raise an exception inside of the interpreter. | |
if (NIL_P(self)) { | |
rb_raise(rb_eScriptError, "Whoa, haus, what'd you do there?"); | |
return Qnil; | |
} | |
// Execute Baz#spew. | |
return rb_funcall(self, rb_intern("spew"), 1, message); | |
} | |
// module Foo | |
// class Bar | |
// def initialize | |
// @postfix = 'world' | |
// end | |
// def say(message) | |
// spew(message) | |
// end | |
// end | |
// end | |
static void init_objects() { | |
VALUE rb_mFoo = rb_define_module("Foo"); | |
VALUE rb_cBar = rb_define_class_under(rb_mFoo, "Bar", rb_cObject); | |
rb_define_method(rb_cBar, "initialize", rb_bar_initialize, 0); | |
rb_define_method(rb_cBar, "say", rb_bar_say, 1); | |
} | |
int main(int argc, char* argv[]) { | |
// #!/usr/bin/ruby | |
// module Foo | |
// class Bar | |
// def spew(message) | |
// return unless message | |
// message.concat(@postfix) | |
// end | |
// end | |
// baz = Foo::Bar.new | |
// baz.say('world') | |
const char script[] = | |
"module Foo\n" | |
" class Bar\n" | |
" def spew(message)\n" | |
" return unless message\n" | |
" message.concat(' ').concat(@postfix)\n" | |
" end\n" | |
" end\n" | |
"end\n" | |
"baz = Foo::Bar.new\n" | |
"baz.say('hello')\n"; | |
// Initialize the virtual machine here. Its all pretty basic. | |
RUBY_INIT_STACK; | |
ruby_init(); | |
ruby_script("main"); | |
// Create our object hierarchy. | |
init_objects(); | |
// Evaluate the script and catch any errors. | |
int rc; | |
VALUE rvalue = rb_eval_string_protect(script, &rc); | |
if (!rc) { | |
// We only want a String back, and no Qnil. | |
if (NIL_P(rvalue) || TYPE(rvalue) != T_STRING) { | |
rb_raise(rb_eTypeError, "Invalid return type."); | |
print_exception(); | |
return 1; | |
} | |
// Print that bad boy out. | |
puts(RSTRING_PTR(rvalue)); | |
} | |
else { | |
print_exception(); | |
return 2; | |
} | |
// Make sure to clean everything up. | |
ruby_finalize(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment