Skip to content

Instantly share code, notes, and snippets.

@mrryanjohnston
Last active September 10, 2020 17:41
Show Gist options
  • Save mrryanjohnston/888f885bae37da37cb2ea9be61c78569 to your computer and use it in GitHub Desktop.
Save mrryanjohnston/888f885bae37da37cb2ea9be61c78569 to your computer and use it in GitHub Desktop.
ruby c extension
#include "ruby.h"
#include "foo_class.h"
VALUE CExtensionModule = Qnil;
void Init_c_extension()
{
CExtensionModule = rb_define_module("CExtension");
rb_init_foo_class();
}
require 'mkmf'
create_makefile('c_extension')
#include "foo_class.h"
VALUE FooClass = Qnil;
VALUE ExampleStructClass = Qnil;
extern VALUE CExtensionModule;
typedef struct example_struct {
char *name;
int struct_id;
} example_struct;
static VALUE rb_example_struct_init(VALUE self, VALUE name) {
example_struct* p;
Check_Type(name, T_STRING);
Data_Get_Struct(self, example_struct, p);
p->name = (char *)malloc(RSTRING_LEN(name) + 1);
memcpy(p->name, StringValuePtr(name), RSTRING_LEN(name) + 1);
return self;
}
static VALUE rb_example_struct_name(VALUE self) {
example_struct* p;
Data_Get_Struct(self, example_struct, p);
return rb_str_new_cstr(p->name);
}
void rb_init_foo_class()
{
FooClass = rb_define_class_under(CExtensionModule, "FooClass", rb_cObject);
rb_define_method(FooClass, "say_hi", rb_foo_class_say_hi, 0);
rb_define_method(FooClass, "say_hi_to", rb_foo_class_say_hi_to, 1);
ExampleStructClass = rb_define_class_under(CExtensionModule, "ExampleStructClass", rb_cObject);
rb_define_alloc_func(ExampleStructClass, rb_foo_class_struct_alloc);
rb_define_method(ExampleStructClass, "initialize", rb_example_struct_init, 1);
rb_define_method(ExampleStructClass, "name", rb_example_struct_name, 0);
}
VALUE rb_foo_class_say_hi(VALUE self)
{
return rb_str_new2("Hello!");
}
VALUE rb_foo_class_say_hi_to(VALUE self, VALUE r_name)
{
VALUE r_greeting = rb_str_new2("Hello, ");
rb_str_append(r_greeting, r_name);
return r_greeting;
}
void example_struct_free(example_struct * self) {
if (self->name != NULL) {
free(self->name);
}
ruby_xfree(self);
}
VALUE rb_foo_class_struct_alloc(VALUE self)
{
return Data_Wrap_Struct(self, NULL, example_struct_free, ruby_xmalloc(sizeof(example_struct)));
}
#include "ruby.h"
void rb_init_foo_class();
VALUE rb_foo_class_say_hi(VALUE self);
VALUE rb_foo_class_say_hi_to(VALUE self, VALUE r_name);
VALUE rb_foo_class_struct(VALUE self, VALUE r_bar);
VALUE rb_foo_class_struct_alloc(VALUE klass);
require "bundler/gem_tasks"
require "rake/testtask"
require "rake/extensiontask"
Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList["test/**/*_test.rb"]
end
Rake::ExtensionTask.new("c_extension") do |ext|
ext.lib_dir = "lib/c_extension"
end
task :default => :test
require "test_helper"
class CExtensionTest < Minitest::Test
def test_that_it_has_a_version_number
refute_nil ::CExtension::VERSION
end
def test_it_says_hi
assert "Hello!", CExtension::FooClass.new.say_hi
end
def test_it_says_hi_to_bob
assert "Hello, Bob", CExtension::FooClass.new.say_hi_to("Bob")
end
def test_struct
assert_equal 'a', CExtension::ExampleStructClass.new('a').name
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment