IO.copy by default consumes the entire source and copies it to the destination. The optional limit parameter sets an upper limit. This can be useful to avoid excessive copies in case of misconfiguration (e.g. reading from an infinite source).
It is expected behaviour of IO.copy(src, dest, limit) to drain the source before reaching limit. In that case, it only returns the amount of bytes read.
If you want to ensure the requested amount is actually copied, you need to explicitly check the return value.
IO.copy(from, to, size) == size || raise IO::EOFError.new
There should be a convenient option to copy an exact amount of bytes.
Possible options:
IO.copy(from, to, *, size): Adds an overload with named parametersize. There might be confusion withIO.copy(from, to, limit)though. We should probably deprecatelimitas positional parameter and require it to be a named parameter. This might be a good idea anyway because the meaning of the positional parameter is not obvious.IO.copy_fully(from, to, size): A different name would reduce the risk of confusion. But calls toIO.copywithlimitparameter might still be misinterpreted.
Add a :+1: reaction to issues you find important.