4

I would like to know how to add a native method written in a C extension to a pre-existing Ruby class ? I only found function that allow you to create new Ruby class, but none which returns a pre-existing class.

yageek
  • 4,115
  • 3
  • 30
  • 48
  • The simple approach imho would be to define the ruby class with the c-extension, and then reopen it in pure ruby. Right? In Ruby you can't redefine a class, you just reopen it and add to it. – nathanvda Jul 24 '13 at 12:31
  • I've not had a problem doing this either way around. AFAIK, the related C functions - e.g. `rb_define_class` will quite happily act to "re-open" classes and modules, because they are in fact the same functions as used in MRI Ruby. – Neil Slater Jul 24 '13 at 13:09

1 Answers1

8

Yes you can. In either case you use rb_define_method (or rb_define_singleton_method for singleton methods). Assuming you have a c function called rb_some_function that expects 1 parameter (in addition to the self parameter) you'd do

rb_define_method(someClass, 
                 "some_function", 
                 RUBY_METHOD_FUNC(rb_some_function),
                 1);

It's up to you whether someClass is a freshly created class (created with rb_define_class_under or rb_define_class) or an existing class. You can use rb_const_get (same as Object's const_get) method to get existing classes.

someClass = rb_const_get(rb_cObject, rb_intern("SomeClass"));

rb_define_class will also fetch an existing class for you (similar to reopening a class in ruby). It will blow up in a similar way if you try to define a class with a superclass and the class already exists with a different one.

Frederick Cheung
  • 83,189
  • 8
  • 152
  • 174
  • As Neil said, does rb_define_class re-open existing class or is it better to use rb_const_get ? – yageek Jul 24 '13 at 13:29
  • 3
    `rb_const_get(rb_cObject, rb_intern("Foo"));` is similar to putting the class-naming symbol `Foo` in your code. E.g. if you would, in Ruby write `def Foo.bar` directly (for whatever reason). Whereas `rb_define_class("Foo", rb_cObject)` is same as writing in Ruby `class Foo`. I would use them accordingly, which means I'd generally avoid the `rb_const_get` approach, unless I was writing an extension that did class meta-programming – Neil Slater Jul 24 '13 at 13:40
  • 1
    If i expect the class to exist i'd tend to use rb_const_get - if the class isn't there then I'd like my code to blow up, rather than just creating a new class. Depends how paranoid I am feeling though – Frederick Cheung Jul 24 '13 at 14:03
  • Ruby use const_get in define_class - so that extra check is redundant. – thomthom Aug 26 '13 at 11:47
  • One thing that concern me if I use `rb_define_class` - I would need to know the super-class of that class. Which may change if the class is not under your control. For that reason I think I prefer `rb_get_const` as I only need to know what namespace it should exist in. – thomthom Dec 16 '13 at 21:44