I want to call a global method in ruby from my C API code. So in ruby:
def giveMeABlock(*args)
puts "Starting giveMeABlock with #{args.inspect}"
yield if block_given?
end
As I've since learned, global functions are actually just private functions in Object, so we can call them from anywhere.
And in C I want to call this method, I can do use rb_funcallv:
VALUE rb_funcallv(VALUE recv, ID mid, int argc, VALUE *argv)
Invokes a method, passing arguments as an array of values. Able to call even private/protected methods.
For this specific example I can do:
rb_funcallv(self, rb_intern("giveMeABlock"), 0, NULL);
And we are able to call the method, though no block is supplied.
To call with a block we have:
VALUE rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VALUE passed_procval)
Same as rb_funcallv_public, except passed_procval specifies the block to pass to the method.
But this, like rb_funcallv_public, can only call public methods. Which means if I try:
rb_funcall_with_block(self, rb_intern("giveMeABlock"), 0, NULL, block);
I get:
private method `giveMeABlock' called for main:Object (NoMethodError)
So why is there no funcall for private methods that can provide a block, or am I missing something? And how do I accomplish this seemingly simple task?
I have realized that I can define the method inside the Object class and then it works (since now it's public), but this seems hacky and assumes I have the ability to alter the ruby source.
I'm late to the party, and you probably don't need this answer anymore, but I'll post for posterity:
The workaround I found for this was to just make the function public
. You can either do it directly from the Ruby code:
public def giveMeABlock(*args)
puts "Starting giveMeABlock with #{args.inspect}"
yield if block_given?
end
Or if that's not an option (e.g. if you can't change the Ruby code you need to run), you can make it public from C code:
rb_funcall(rb_cObject, rb_intern("public"), 1, rb_id2sym(rb_intern("giveMeABlock")))
Now that it's public, you can call it with rb_funcall_with_block
.