views:

1276

answers:

2

I'm trying to use select on STDIN and a TCP socket in Ruby, but for some reason, the value returned from select never seems to match one of the choices; it looks like it's the socket that's being returned, but it doesn't match using == (or equal?). Can anyone tell me why the result returned from select doesn't match the objects I passed in, and what I should be doing differently here?

server = TCPSocket::new("irc.freenode.net", 7000)
server.puts "NICK MyBot"
server.puts "USER #{ENV['USER']} 0 * :My Bot"

# <snip definitions>

while (!$done)
  results = select([server, STDIN], nil, nil)
  if results[0] == STDIN
    puts "Reading from STDIN"
    execute_command
  elsif results[0] == server
    puts "Reading from server"
    receive_data
  else
    puts "Something's wrong... results[0]: #{results[0]}, server: #{server}"
    puts "IDs: results[0]: #{results[0].__id__}, server: #{server.__id__}"
    exit 1
  end
end

Here's what I get when I run this:

Something's wrong... results[0]: #<TCPSocket:0x33c390>, server: #<TCPSocket:0x33c390>
IDs: results[0]: 1695840, server: 1695990

I'm running Ruby version 1.8.6 on Mac OS X.

$ ruby --version
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
$ which ruby
/usr/bin/ruby
A: 

Do you get the same results if you use .equal? or .eql?

http://ruby-doc.org/core/classes/Object.html#M000341

== may be overridden by subclasses, but .equal? is not supposed to be. The main question here is actually why the same object, when compared to itself via ==, is returning false. You may need to check out the source or docs of the TCPSocket class.

Sarah Mei
Same results with .equal? If I try printing the __id__ of each object, they are different: puts "IDs: results[0]: #{results[0].__id__}, server: #{server.__id__}"Gives me: `IDs: results[0]: 1695840, server: 1695990`
Brian Campbell
+6  A: 

The fist element of the Array returned by select is an Array of the IO objects that are ready. So you should compare the STDIN and server to results[0][0]. Or better check, if the socket is in the results Array

...
if results[0].include? STDIN
  ...
elsif results[0].include? server 
 ...
...
jgre
Yep, this is it. I guess I missed that the results were an array of arrays; and confusingly, the array printed exactly the same as the single socket in my debugging statement.I ended up a loop through the elements in results[0] instead of using include?, but your answer got me started. Thanks!
Brian Campbell
Ah, interesting. I forgot that printing an array via "#{array}" just prints the elements. The dangers of print-statement debugging I guess. :)
Sarah Mei
In Ruby1.9 this has improved and [1, 2, 3].to_s gives "[1, 2, 3]" instead of "123". With 1.8 you get this behavior by calling Array#inspect.
jgre