Question

I am storing an array of procs in a Ruby C extension and I need to go through and instance_eval each proc. The problem is that instance_eval only accepts blocks, not procs. This is not an issue in Ruby where I can simply go:

proc_list.each { |my_proc|
    @receiver.instance_eval(&my_proc)
}

However I am unsure how to go about this using the Ruby C API.

Does anyone have any ideas how I might accomplish this?

Was it helpful?

Solution

From the pickaxe, p. 871 (1.9 edition)

VALUE rb_iterate( VALUE (*method)(), VALUE args, VALUE (*block)(), VALUE arg2 )

Invokes method with argument args and block block. A yield from that method will invoke block with the argument given to yield and a second argument arg2.

So pass your Proc objects as arg2 and define a (*block)() function that just forwards the passed value to the Proc's #call method.

Something like

for (i = 0; i < numProcs; i++)
{
  rb_iterate( forwarder, receiver, block, procs[i] );
}

/*...*/

VALUE forwarder(VALUE receiver)
{
  // the block passed to #instance_eval will be the same block passed to forwarder
  return rb_obj_instance_eval(0, NULL, receiver);
}
VALUE block(VALUE proc)
{
  return rb_funcall(proc, rb_intern("call"), 0);
}

I haven't tested this code, but it's consistent with the caveats in this article.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top