noah.easterly@gmail.com
4/7/2007 6:07:00 PM
On Apr 7, 1:08 pm, "Kent Sibilev" <ksr...@gmail.com> wrote:
> You should wrap your rb_yield call with rb_ensure. From README.EXT:
>
> VALUE rb_ensure(VALUE (*func1)(), void *arg1, void (*func2)(), void *arg2)
>
> Calls the function func1 with arg1 as the argument, then calls func2
> with arg2 if execution terminated. The return value from
> rb_ensure() is that of func1.
Hmm.... this doesn't seem to have the desired effect. I'm pretty sure
rb_ensure() is just for handling exceptions, not breaks.
According to ruby.h and the Pickaxe, the function def'n has changed a
bit too. From Programming Ruby(2nd ed):
VALUE rb_ensure(VALUE(*body)(), VALUE args, VALUE(*ensure)(), VALUE
eargs)
Executes body with the given args. Whether or not an exception is
raised, execute ensure with the given eargs after body has completed.
So it seems that rb_ensure is just for exceptions, not 'break'. I
tried tweaking my code to use it anyway, but the ensure call is still
bypassed when there is a break. For example:
>>> lib.c
void func( int n, int (*callback)(void) )
{
printf("before callback...\n");
if (callback() < 0)
goto cleanup;
printf("after callback...\n");
cleanup:
printf("in cleanup...\n");
}
>>> ext.c
static void
my_ensure(void * ptr)
{
*(int *)ptr = -1;
}
static int
meth_callback(void)
{
int retval = 0;
rb_ensure(rb_yield, Qnil, my_ensure, &retval);
return retval;
}
// ...
>>> test.rb
require 'ext'
YYY.new.meth(100) { } # outputs "before callback...\n", "in cleanup...
\n"
YYY.new.meth(100) { break } # outputs "before callback...\n"
Which makes sense if, when there is no break, the my_ensure func gets
called (as it should), so processing skips to cleanup, and when there
is a break, the ensure func does not get called, and processing skips
back to the ruby script.
I suppose I could switch to having people 'raise BreakException',
rather than 'break' within the block, but that seems like its hobbling
the ruby language.
Thanks for the idea, though!