Reputation: 541
I've been using OilyPNG (a set of C extensions for working with PNG's) and I'd like to start adding some of my own methods. As such, I coded up a simple little C extension that creates the class Hola
and includes the methods Hola.bonjour
(which responds with a simple "hello") and Hola.wazzup(input)
which spits the input right back.
OilyPNG is a module that contains a single class :Canvas
with a bunch of methods :decode_png_image_pass
, :from_data_url
, :from_rgb_stream
, etc.). I'd like to add my methods (bonjour
and wazzup
) to the Canvas
so I can start using them. How do I do this?
It seems like this is a very basic Ruby question, but I can't seem to find it addressed anywhere. I've tried (among MANY other things) the following:
module ChunkyPNG
class Canvas
include Hola
end
end
...but it returns the following:
Error: #TypeError: wrong argument type Class (expected Module)
All I want to do is something simple like creating a new Canvas object, then running my method, i.e. OilyPNG::Canvas.new.bonjour
and I'm totally stuck.
UPDATE: The C code used to generate the extension
#include <ruby.h>
/* our new native method; it just returns the string "bonjour!" */
static VALUE hola_bonjour(VALUE self) {
return rb_str_new2("bonjour, Zack!");
}
void Init_hola(void) {
VALUE klass = rb_define_module("Hola"); /*DEFINED AS A MODULE*/
rb_define_singleton_method(klass, "bonjour", hola_bonjour, 0);
}
UPDATE 2:
Finally got it working - using rb_define module
in the C code, followed by defining the methods as rb_define_method
(instead of as singletons). Then build the gem, install it, then require the .so file, then open up OilyPNG to include the Hola module, as follows:
module OilyPNG
class Canvas < ChunkyPNG::Canvas
def your_method
puts "hello"
end
include Hola
end
end
Then load a png file as a test object:
test = OilyPNG::Canvas.from_file("C:/code/testfiles/orange.png"); nil
(the nil is to prevent Sketchup from crashing when it tries to send the PNG object to the command line), and then testing the output of:
test.bonjour
And it works!
Upvotes: 0
Views: 13424
Reputation: 2878
module OilyPNG
class Canvas < ChunkyPNG::Canvas # You must match the superclass when opening class and adding more definitions
def your_method
puts "hello"
end
include Hola # this will "insert" the Hola module at this point in the code... not sure what Hola contains so, not sure if that works or not.
end
end
Looking at the source for OilyPNG the above should work...
Not sure why you got that error. Given this works here is why: You have to match the classes, super class when reopening it.
Based on this article: http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-minutes-100.html by the great Peter Cooper, I believe you should be using rb_define_method
, not rb_define_singleton_method
If you are still having trouble, start with peter's example, then adapt it to your needs.
Upvotes: 1
Reputation: 434596
You say that you
[...] coded up a simple little C extension that creates the class "Hola"
so Hola
is a class. But include
expects a module, not a class. You have to rebuild your Hola
as a module if you want to include Hola
to patch ChunkyPNG::Canvas
.
Consider this example:
class C
end
class D
include C
end
That will give you exactly the same TypeError
that you're seeing. However, if you say:
module M
end
class E
include M
end
then it will work just fine.
Upvotes: 1