如何在Ruby 1.9 C扩展中将块转换为Proc?

rub*_*eca 6 c ruby block ruby-1.9 ruby-c-extension

我正在编写Ruby 1.9 C扩展,我想在ruby中执行以下操作:

notifier = Notifier.new
notifier.on 'click' do
  puts "clicked!"
end
Run Code Online (Sandbox Code Playgroud)

现在问题是在C方法上,我只"接收"一个块,据我所知,它甚至不是一个参数:我只能用来调用rb_yield.

所以我的问题是:在Ruby 1.9 C扩展上是否有办法将块转换为proc或者其他东西,所以我可以将它存储在我的模块中,并在我想要/需要它时稍后调用它?就像一个异步回调!

我已经使用Procs/lambdas实现了这个,但是直接使用块语法真是太丑了.

mu *_*ort 5

在Ruby C源代码中,您将看到proc.c:

/*
 * call-seq:
 *   proc   { |...| block }  -> a_proc
 *
 * Equivalent to <code>Proc.new</code>.
 */

VALUE
rb_block_proc(void)
{
    return proc_new(rb_cProc, FALSE);
}
Run Code Online (Sandbox Code Playgroud)

Proc.new做到这一点:

创建Proc绑定到当前上下文的新对象.Proc::new可以仅在具有附加块的方法内调用没有块,在这种情况下,该块被转换为Proc对象.

所以你会做这样的事情:

VALUE p = rb_block_proc();
/* and then store `p` somewhere convenient */
Run Code Online (Sandbox Code Playgroud)

然后再调用块/ Proc:

rb_funcall(p, rb_intern("call"), 0);
Run Code Online (Sandbox Code Playgroud)

rb_funcall几乎是C版的p.send(:call).