The note about the idiomatic Ruby version of this (each on a range) being slower than the tested version (while loop) is very interesting.
This looks like an opportunity for the Ruby interpreter to optimise: if the range is excessively large, it could decide itself to loop over the bounds rather than instantiating the entire range.