Index: enumerator.c =================================================================== --- enumerator.c (revision 36594) +++ enumerator.c (working copy) @@ -105,7 +105,7 @@ VALUE rb_cEnumerator; VALUE rb_cLazy; static ID id_rewind, id_each, id_new, id_initialize, id_yield, id_call; -static ID id_eqq, id_next, id_result, id_lazy, id_receiver, id_arguments, id_method; +static ID id_eqq, id_next, id_result, id_lazy, id_receiver, id_arguments, id_method, id_source; static VALUE sym_each, sym_cycle; VALUE rb_eStopIteration; @@ -567,6 +567,7 @@ result = rb_block_call(obj, id_each, 0, 0, next_ii, obj); e->stop_exc = rb_exc_new2(rb_eStopIteration, "iteration reached an end"); rb_ivar_set(e->stop_exc, id_result, result); + rb_ivar_set(e->stop_exc, id_source, obj); return rb_fiber_yield(1, &nil); } @@ -1724,6 +1725,27 @@ return rb_attr_get(self, id_result); } +/* + * call-seq: + * source -> value + * + * Returns the enumerator responsible for raising this instance. + * + * e = [].each + * + * begin + * e.next + * rescue StopIteration => ex + * puts ex.source + * end + * + */ +static VALUE +stop_source(VALUE self) +{ + return rb_attr_get(self, id_source); +} + void InitVM_Enumerator(void) { @@ -1773,6 +1795,7 @@ rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError); rb_define_method(rb_eStopIteration, "result", stop_result, 0); + rb_define_method(rb_eStopIteration, "source", stop_source, 0); /* Generator */ rb_cGenerator = rb_define_class_under(rb_cEnumerator, "Generator", rb_cObject); @@ -1808,6 +1831,7 @@ id_receiver = rb_intern("receiver"); id_arguments = rb_intern("arguments"); id_method = rb_intern("method"); + id_source = rb_intern("source"); sym_each = ID2SYM(id_each); sym_cycle = ID2SYM(rb_intern("cycle")); Index: test/ruby/test_enumerator.rb =================================================================== --- test/ruby/test_enumerator.rb (revision 36594) +++ test/ruby/test_enumerator.rb (working copy) @@ -185,6 +185,16 @@ assert_equal(res, exc.result) end + def test_stop_source + e = [].each + begin + e.next + fail + rescue StopIteration => ex + assert_equal(e, ex.source) + end + end + def test_next_values o = Object.new def o.each