Proposal: stop raising when block passed to IO#each_* closes the IO
As of #17661, all of the enumeration methods on
IOError when the given block closes the
IO. For example, the following code raises an
IOError if the peer sends a line containing only
socket.each_line do |line| if line.casecmp?("quit\n") socket.puts "Goodbye" socket.close end end
In this example, it’s trivial to
break after closing the client socket. However, in real code, it’s likely that the command-handling code will be further away from the loop and unable to
break out of the loop. Either the command-handling method and all intervening methods need to pass an indication of whether to keep reading back down the stack, or the block needs to include an explicit
break if io.closed?.
In my experience, when I close an
IOwithin a read loop, I intend to immediately stop reading as well. It would be more agreeable if
each_line et al. simply stopped reading when the
IO is closed in the block instead of raising
I recognize this may be considered a breaking change. The patch for #17661 was backported to 3.0, and
each_line has behaved this way for longer. This may be workable as an option to the enumeration methods, but I’m not sure an option is worth its weight compared to explicit
break if io.closed?. I’m mostly asking for a decision on whether the implicit behavior is worth changing for convenience and developer happiness (and aware the answer may be no).
I’ve attached a patch containing a sample implementation for
IO#each_line and updated specs. I believe this change can be implemented similarly for all other enumeration methods.
No data to display