2012-01-17 54 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