Как мне преобразовать Блок в Proc в расширении Ruby 1.9 C? - PullRequest
6 голосов
/ 18 января 2012

Я пишу расширение Ruby 1.9 C и хочу сделать следующее в ruby:

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

Теперь проблема в том, что на методе C я только "получаю" блоки, насколько я знаю, это даже не параметр: я просто могу вызвать с помощью rb_yield.

Так что мой вопрос: есть ли способ на расширении Ruby 1.9 C, чтобы преобразоватьзаблокировать в процесс или что-то, чтобы я мог сохранить его в моем модуле, и вызывать его позже, когда я хочу / нуждаюсь в них?Как асинхронный обратный вызов!

Я уже реализовал это с помощью Procs / lambdas, но просто уродливо не использовать синтаксис блока напрямую.

1 Ответ

5 голосов
/ 18 января 2012

В источнике 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).

...