Bug #19354
closedIssues with arguments validation in IO.read
Description
I've noticed a strange error message when IO.read
is called with additional positional argument:
IO.read("a.txt", 3, 0, {mode: "r+"})
# (irb):2:in `read': wrong number of arguments (given 3, expected 0..2) (ArgumentError)
But I would expect receiving given 4, expected 1..3
as far as the first argument (file name) is mandatory and all the other arguments - are optional.
I've encountered another related issue - looks like existing of a file with specified name is checked before number of arguments.
So when passed additional argument and specified a name of not existing file - I receive error about wrong file name, but would expect more basic and essential error about wrong number of arguments:
IO.read("b.txt", 3, 0, {mode: "r+"})
# (irb):3:in `read': No such file or directory @ rb_sysopen - b.txt (Errno::ENOENT)
Updated by andrykonchin (Andrew Konchin) over 2 years ago
- ruby -v changed from 3.2.1, 3.2.1 to 3.2.0, 3.2.1
Updated by andrykonchin (Andrew Konchin) over 2 years ago
- ruby -v changed from 3.2.0, 3.2.1 to 3.2.0, 3.1.3
Updated by nobu (Nobuyoshi Nakada) over 2 years ago
- Status changed from Open to Feedback
IO.read
opens the file given as the first argument, then delegates the other arguments to IO#read
on the instance.
Your error happens in the delegated IO#read
.
Since 3.0, keyword arguments are separated from mere hashes.
I think you may want to write:
IO.read("a.txt", 3, 0, mode: "r+")
Updated by andrykonchin (Andrew Konchin) over 2 years ago
Yeah, I understand that it's caused by the way how IO.read
is implemented.
My point is that from the end-user point of view current error message (given 3, expected 0..2
) is slightly misleading/confusing.
Updated by Eregon (Benoit Daloze) over 2 years ago
I think the current error could be acceptable if it's clear IO#read is in the backtrace.
But it's not part of the backtrace currently (and on top it's not possible to differentiate IO.read and IO#read from the backtrace):
$ ruby -e 'IO.read("a.txt", 3, 0, {mode: "r+"})'
-e:1:in `read': wrong number of arguments (given 3, expected 0..2) (ArgumentError)
from -e:1:in `<main>'
And so this is rather inconsistent (in expected args) with:
$ ruby -e 'IO.read("a.txt", 3, 0, {mode: "r+"}, 5, 6)'
-e:1:in `read': wrong number of arguments (given 6, expected 1..4) (ArgumentError)
from -e:1:in `<main>'
The second error in the description seems clearly wrong behavior.
So I guess we should check args more strictly in IO.read itself, before calling IO#read.