6

I'm writing a Ruby 1.9 C extension and I want to do the following in ruby:

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

Now the problem with this is that on the C method, I only "receive" a block, and, as far as I know, it's not even a parameter: I just can call with with rb_yield.

So my question is: is there a way on a Ruby 1.9 C extension, to transform a block into a proc or something, so I can store it inside my module, and call it later whenever I want/need them? Like an async callback!

I already implemented this with Procs/lambdas, but it's just ugly not to use the block syntax directly.

Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107
rubenfonseca
  • 699
  • 10
  • 26
  • 5
    Have you seen [this](http://banisterfiend.wordpress.com/2008/09/25/metaprogramming-in-the-ruby-c-api-part-one-blocks/) article (especially "explicit blocks" paragraph)? It might be outdated but otherwise it looks like what you need. – KL-7 Jan 17 '12 at 23:04
  • Sorry, I can't answer your question, because I don't know C nor the YARV C API, but as a clarification to other readers, your question basically is: "how do I do `def on(&blk) end` from C", right? – Jörg W Mittag Jan 18 '12 at 01:42

1 Answers1

5

In the Ruby C source you'll see this in 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);
}

and Proc.new does this:

Creates a new Proc object, bound to the current context. Proc::new may be called without a block only within a method with an attached block, in which case that block is converted to the Proc object.

So you'd do something like this:

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

and then later on, to call the block/Proc:

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

That rb_funcall is pretty much the C version of p.send(:call).

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • @rubenfonseca: Simple once you know what to do :) You need to have a grepping-familiarity of the C source to write C extensions. – mu is too short Jan 18 '12 at 19:22