Calling and passing blocks in a C extension

Hello

How do I do the equivalent of the code below in a C extension?

def foo(&block)
  x = 0
  my_iterator do |b|
    b.process(&block)
    x += 1
  end
  return x
end

I tried lots of different combinations of rb_iterate() and rb_proc_new()
but it turned into one big mess :s

Thanks,
Andre

I've just noticed it works in ruby 1.9 but segfaults in 1.8.6... Can
anyone spot a reason? (It seems to be segfaulting when rb_yield() is
called in my_iterator()).

#include <ruby.h>

static VALUE
call_block(VALUE x, VALUE block)
{
    return rb_funcall(block, rb_intern("call"), 1, x);
}

static VALUE
process_i(VALUE b, void *data)
{
    VALUE *d = (VALUE *)data;
    int *x = (int *)d[0];
    VALUE block = d[1];

    *x += 1;
    return rb_iterate(rb_ary_each, b, call_block, block);
}

static VALUE
my_iterator(VALUE dummy)
{
    VALUE ary = rb_ary_new3(2, INT2FIX(10), INT2FIX(20));
    return rb_yield(ary);
}

static VALUE
foo(int argc, VALUE *argv, VALUE self)
{
    VALUE block;
    int x = 0;
    VALUE data[2];
    data[0] = (VALUE)&x;
    data[1] = block;
    rb_scan_args(argc, argv, "00&", &block);
    rb_iterate(my_iterator, 0, process_i, (VALUE)data);
    return(self);
}

void
Init_a(void)
{
    VALUE cA = rb_define_class("A", rb_cObject);
    rb_define_method(cA, "initialize", foo, -1);
}

Thanks,
Andre

···

On Fri, 2007-11-23 at 05:33 +0900, Andre Nathan wrote:

I tried lots of different combinations of rb_iterate() and rb_proc_new()
but it turned into one big mess :s

Guy Decoux pointed me my stupid mistake...

static VALUE
foo(int argc, VALUE *argv, VALUE self)
{
    VALUE block;
    int x = 0;
    VALUE data[2];

+ rb_scan_args(argc, argv, "00&", &block);

    data[0] = (VALUE)&x;
    data[1] = block;

- rb_scan_args(argc, argv, "00&", &block);

    rb_iterate(my_iterator, 0, process_i, (VALUE)data);
    return(self);
}

Andre