Exceptions raised from within an enumerated method lose part of their stacktrace
Consider the following code:
class Test include Enumerable def each(&block) raise "Boom" end end def execution_method_a Test.new.to_enum(:each).next end def execution_method_b Test.new.each do # Never gets run end end begin execution_method_a rescue RuntimeError => e puts "Using to_enum and next" puts e.message puts e.backtrace end begin execution_method_b rescue RuntimeError => e puts "Calling a block directly" puts e.message puts e.backtrace end
When this file (located at lib/script.rb) is run the result is:
Using to_enum and next Boom lib/script.rb:5:in `each' lib/script.rb:1:in `each' Calling a block directly Boom lib/script.rb:5:in `each' lib/script.rb:14:in `execution_method_b' lib/script.rb:29:in `<main>'
This is a little unusual. Effectively, if we create an enumerator and use
next to iterate through the results, the backtrace is modified to the point where the calling method(s) are entirely lose. Notice when the
each method is used directly and an exception is thrown, we see
execution_method_b present in the stacktrace, but if we use
next we do not see
execution_method_a present at all.
This means that if there is some code that uses the enumerator/next approach deep within a callstack, the exception that comes out does not have any crucial information of where the call originated from.