2012-01-17 15 views
6

Tôi đang viết một phần mở rộng của Ruby 1,9 C và tôi muốn làm như sau trong ruby:Làm thế nào để chuyển đổi một Khối thành một Proc trong một phần mở rộng Ruby 1.9 C?

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

Bây giờ vấn đề với điều này là theo phương pháp C, tôi chỉ "nhận" một khối, và, theo như tôi biết, nó thậm chí không phải là một tham số: Tôi chỉ có thể gọi với rb_yield. Vì vậy, câu hỏi của tôi là: là có một cách trên một phần mở rộng Ruby 1.9 C, để chuyển đổi một khối thành một proc hoặc một cái gì đó, vì vậy tôi có thể lưu nó bên trong mô-đun của tôi, và gọi nó sau này bất cứ khi nào tôi muốn/cần chúng? Không. Giống như một cuộc gọi lại không đồng bộ!

Tôi đã triển khai thực hiện điều này với Procs/lambdas, nhưng thật xấu xí khi không sử dụng cú pháp khối trực tiếp.

+5

Bạn đã thấy [this] (http://banisterfiend.wordpress.com/2008/09/25/metaprogramming-in-the-ruby-c-api-part-one-blocks/) bài viết (đặc biệt là "tường minh chặn "đoạn văn"? Nó có thể đã lỗi thời nhưng nếu không nó trông giống như những gì bạn cần. –

+0

Xin lỗi, tôi không thể trả lời câu hỏi của bạn, vì tôi không biết C và API YARV C, nhưng làm rõ cho người đọc khác, câu hỏi của bạn về cơ bản là: "làm cách nào để làm' def on (& blk) end' từ C ", phải không? –

Trả lời

5

Trong nguồn của Ruby C bạn sẽ thấy điều này trong 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 thực hiện điều này:

Tạo một đối tượng mới Proc, ràng buộc với bối cảnh hiện nay. Proc::new có thể được gọi mà không có khối chỉ trong một phương pháp có khối được đính kèm, trong trường hợp đó khối đó được chuyển đổi thành đối tượng Proc.

Vì vậy, bạn muốn làm điều gì đó như thế này:

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

và sau đó sau này, để gọi khối/Proc:

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

Đó rb_funcall là khá nhiều phiên bản C p.send(:call).

+0

Ôi trời ơi, thật đơn giản và rõ ràng! CẢM ƠN BẠN! – rubenfonseca

+0

@rubenfonseca: Đơn giản một khi bạn biết phải làm gì :) Bạn cần phải có một sự quen thuộc của nguồn C để viết phần mở rộng C. –