Ruby和C API:rb_funcall_with_block在全局方法上?如何从C中调用Ruby全局方法?

qeeaahzv  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(89)

我想从我的C API代码中调用一个ruby中的全局方法。在Ruby中:

def giveMeABlock(*args)
  puts "Starting giveMeABlock with #{args.inspect}"
  yield if block_given?
end

正如我后来了解到的那样,全局函数实际上只是Object中的私有函数,所以我们可以从任何地方调用它们。
在C中,我想调用这个方法,我可以使用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.

对于这个具体的例子,我可以这样做:

rb_funcallv(self, rb_intern("giveMeABlock"), 0, NULL);

我们能够调用该方法,尽管没有提供任何块。
要调用块,我们有:

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.

但是,像rb_funcallv_public一样,它只能调用公共方法。这意味着如果我尝试:

rb_funcall_with_block(self, rb_intern("giveMeABlock"), 0, NULL, block);

我得到:

private method `giveMeABlock' called for main:Object (NoMethodError)

那么,为什么没有可以提供块的私有方法的funcall,或者我错过了什么?如何完成这个看似简单的任务?
我已经意识到我可以在Object类中定义方法,然后它就可以工作了(因为现在它是公共的),但这似乎很奇怪,并且假设我有能力改变Ruby源代码。

tyg4sfes

tyg4sfes1#

我迟到了,你可能不再需要这个答案了,但我会为后代发布:
我找到的解决方法是只做函数public。您可以直接从Ruby代码中执行此操作:

public def giveMeABlock(*args)
  puts "Starting giveMeABlock with #{args.inspect}"
  yield if block_given?
end

或者如果这不是一个选择(例如,如果你不能改变你需要运行的Ruby代码),你可以从C代码中公开它:

rb_funcall(rb_cObject, rb_intern("public"), 1, rb_id2sym(rb_intern("giveMeABlock")))

现在它是公共的,您可以使用rb_funcall_with_block调用它。

相关问题