Skip to content

Instantly share code, notes, and snippets.

@johnbellone
Last active December 14, 2015 03:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnbellone/5020125 to your computer and use it in GitHub Desktop.
Save johnbellone/5020125 to your computer and use it in GitHub Desktop.
Marrying Ruby and C
// $ 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