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

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

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

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

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