'C' based iterators

Fellow Rubyists,
Been cracking my skull on how to code iterators in ‘C’, and need a few
pointers:

  1. rb_iter_break() is the equvalent of “break”, what is the equivalent
    of “next”?

  2. Scoping tricks

    bar = nil
    foo.each { |bar|
    next if bar.capacity < size
    break
    }

In Ruby, I can do scoping tricks as above, so that I get the value of
bar if the test fails outside of the block. How the heck can I do that
in ‘C’?

TIA.
/squidster

1. rb_iter_break() is the equvalent of "break", what is the equivalent
of "next"?

Well, you can call rb_jump_tag() if you hardcode the value of TAG_NEXT,
the best is just to do nothing :-))

2. Scoping tricks
<ruby code>
bar = nil
foo.each { |bar|
   next if bar.capacity < size
   break
}
</ruby>

In Ruby, I can do scoping tricks as above, so that I get the value of
bar if the test fails outside of the block. How the heck can I do that
in 'C'?

Well, to write the same in C you use rb_iterate(). From README.EXT

VALUE rb_iterate(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2)

Calls the function func1, supplying func2 as the block. func1 will be
called with the argument arg1. func2 receives the value from yield as
the first argument, arg2 as the second argument.

For example

pigeon% cat a.c
#include <ruby.h>

static VALUE a_iter(i, j)
    VALUE i, *j;
{
    *j = i;
    if (TYPE(i) != T_ARRAY || RARRAY(i)->len < 3) {
        rb_iter_break();
    }
    /* this is a next */
    return Qnil;
}

static VALUE a_uu(obj)
    VALUE obj;
{
    VALUE a = Qnil;
    rb_iterate(rb_each, obj, a_iter, (VALUE)&a);
    rb_p(a);
    return obj;
}

void Init_a()
{
    rb_define_method(rb_cArray, "uu", a_uu, 0);
}
pigeon%

pigeon% ruby -ra -e '[[1,2], 1].uu'
[1, 2]
pigeon%

pigeon% ruby -ra -e '[[1,2, 3], 1, [1,2,4]].uu'
1
pigeon%

pigeon% ruby -ra -e '[[1,2, 3], [1,2,4]].uu'
[1, 2, 4]
pigeon%

Guy Decoux