2012-01-17 51 views
6

我正在写一个Ruby 1.9的C扩展,我想要做的红宝石以下:如何在Ruby 1.9 C扩展中将块转换为Proc?

notifier = Notifier.new 
notifier.on 'click' do 
    puts "clicked!" 
end 

现在有了这个问题是关于C的方法,我只是“接收”的块,并且,据我所知,这甚至不是一个参数:我只需要拨打rb_yield即可。

所以我的问题是:是否有一种Ruby 1.9 C扩展的方法,将块转换为proc或某些东西,所以我可以将它存储在模块中,并在需要/需要时再调用它?就像异步回调一样!

我已经用Procs/lambdas实现了这一点,但直接使用块语法只是丑陋而已。

+5

你见过[this](http://banisterfiend.wordpress.com/2008/09/25/metaprogramming-in-the-ruby-c-api-part-one-blocks/)文章(尤其是“显式的块“段)?它可能已过时,但看起来像你所需要的。 – 2012-01-17 23:04:07

+0

对不起,我不能回答你的问题,因为我不知道C也没有YARV C API,但是作为对其他读者的一个澄清,你的问题基本上是:“我怎么做'def on(&blk)end'来自C“,对吗? – 2012-01-18 01:42:11

回答

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); 
} 

Proc.new做到这一点:

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

所以,你会做这样的事情:

VALUE p = rb_block_proc(); 
/* and then store `p` somewhere convenient */ 

再后来,调用块的/ proc:

rb_funcall(p, rb_intern("call"), 0); 

rb_funcall是相当多的C版p.send(:call)

+0

噢,我的上帝,那么简单明了!谢谢! – rubenfonseca 2012-01-18 17:12:16

+0

@rubenfonseca:一旦你知道该怎么做,简单:)你需要熟悉C源代码来编写C扩展。 – 2012-01-18 19:22:52