diff --git a/ext/spidermonkey/ruby_land_proxy.c b/ext/spidermonkey/ruby_land_proxy.c index b64935f..2183012 100644 --- a/ext/spidermonkey/ruby_land_proxy.c +++ b/ext/spidermonkey/ruby_land_proxy.c @@ -163,8 +163,14 @@ each(VALUE self) for (i = 0; i < length; ++i) { jsval element; + int state; JCHECK(JS_GetElement(proxy->context->js, value, (signed) i, &element)); - rb_yield(convert_to_ruby(proxy->context, element)); + rb_protect(rb_yield, convert_to_ruby(proxy->context, element), &state); + if (state) + { + REMOVE_JROOTS; + rb_jump_tag(state); + } } } else @@ -200,7 +206,13 @@ each(VALUE self) VALUE key = convert_to_ruby(proxy->context, js_key); VALUE value = convert_to_ruby(proxy->context, js_value); - rb_yield(rb_ary_new3(2, key, value)); + int state; + rb_protect(rb_yield, rb_ary_new3(2, key, value), &state); + if (state) + { + REMOVE_JROOTS; + rb_jump_tag(state); + } JUNROOT(js_value); JUNROOT(js_key); diff --git a/test/johnson/spidermonkey/ruby_land_proxy_test.rb b/test/johnson/spidermonkey/ruby_land_proxy_test.rb index b4ef770..ba74635 100644 --- a/test/johnson/spidermonkey/ruby_land_proxy_test.rb +++ b/test/johnson/spidermonkey/ruby_land_proxy_test.rb @@ -147,6 +147,19 @@ def test_supports_each_on_things_that_arent_arrays assert_equal({ 'foo' => 'fooval', 'bar' => 'barval', 0 => 42 }, values) end + def test_each_passes_an_exception + proxy = @context.evaluate("x = { foo: 'fooval', bar: 'barval' }; x[0] = 42; x") + values = {} + + assert_raise(RuntimeError) do + proxy.each do |k, v| + values[k] = v + raise "splat" if values.keys.size == 2 + end + end + assert_equal({ 'foo' => 'fooval', 'bar' => 'barval' }, values) + end + def test_is_enumerable proxy = @context.evaluate("[1, 2, 3]") assert_kind_of(Enumerable, proxy)