I’m confused about how IO#select works in Ruby. I’m told here that it should only return the given IO objects if they are ready to be read. However, I’m getting IO objects returned even when eof? is true.
Am I missing something?
Here’s some code that exhibits my confusion:
require 'open3'
stdin, stdout, stderr, thread = Open3.popen3('true')
eval_print = lambda {|code| puts "#{code} -> #{eval(code).inspect}" }
eval_print.call('stdout')
eval_print.call('stderr')
eval_print.call('select([stdout, stderr], nil, nil, 1)')
eval_print.call('stdout.eof?')
eval_print.call('stderr.eof?')
eval_print.call('stdout.gets')
eval_print.call('stderr.gets')
eval_print.call('select([stdout, stderr], nil, nil, 1)')
The output of this code (on Ruby version 1.9.2p136) is:
stdout -> #<IO:fd 5>
stderr -> #<IO:fd 7>
select([stdout, stderr], nil, nil, 1) -> [[#<IO:fd 5>, #<IO:fd 7>], [], []]
stdout.eof? -> true
stderr.eof? -> true
stdout.gets -> nil
stderr.gets -> nil
select([stdout, stderr], nil, nil, 1) -> [[#<IO:fd 5>, #<IO:fd 7>], [], []]
Shouldn’t select return nil in both of those cases?
I don’t blame you for being a little confused, the official docs are, shall we say, a little thin on what
selectis supposed to do.IO.selectis probably just a thin wrapper around theselectsystem call so we’ll have a look at that (which is quite well documented). From the Linux man pages:Emphasis mine. So,
selectis more about “will it block” than it is about “are there bytes waiting for me” and an EOF is a non-blocking state soselectconsiders a file descriptor that is in an end-of-file condition to be ready for reading.