The problem in question seems to be that only every OTHER line of
terminal input is handled by elsif input == STDIN. Here is the complete
code, with some masked stuff
Code:
require ‘socket’
require ‘protocol.rb’
#Settings for the server we’re connecting too
class AmityClient
include AmityPackets
def initialize
#Bool to check if we've received a Ctrl-C, so we can shut down and
clean up nicely.
@interrupted = false
@hostname = "MASKED"
@port = 6002
@username = "amity"
@mppass = "MASKED"
begin
puts "Trying to connect to #{@hostname} on #{@port}"
@sock = TCPSocket.new(@hostname, @port)
sendLogin(@sock, @username, @mppass)
sendChat(@sock, "-- Amity b0.1 connected --")
run()
rescue IOError
puts "-- Socket closed --"
rescue
puts "Error: #{$!}"
end
end
def run
while 1 #Enter Infinite Loop
#Trap a Ctrl-C, and turn on interrupted
trap("INT") {@interrupted = true}
#select input
results = select([@sock, STDIN], nil, nil)
if results != nil then
for input in results[0]
if input == @sock then #Socket Input found
#Socket stuff here
elsif input == STDIN #Standard Input found
if gets.chomp! == "!quit" then
cleanupAndExit
else
puts gets.chomp!
end
end #if
end #for
end #if
if @interrupted
puts "\nInterrupted! Cleaning up..."
cleanupAndExit
end
end #while
end #def
def cleanupAndExit
@sock.close
sendChat(@sock, “User quit Amity Client”)
exit
end
end
interrupted = false
trap(“INT”) {interrupted = true}
amity = AmityClient.new
if interrupted
puts “Interrupted”
exit
end
On 11/20/2009 04:12 PM, Dylan Lukes wrote:
The problem in question seems to be that only every OTHER line of
terminal input is handled by elsif input == STDIN. Here is the complete
code, with some masked stuff
Think about it for a moment: do you believe that such an obvious error
in select could have slipped by all tests? No? OK, I don’t either.

The bug is with 99% likeliness in your code. You have a bug in your
input reading code. Look at how you use gets.
Cheers
robert
if gets.chomp! == "!quit" then
cleanupAndExit
else
puts gets.chomp!
end
Note how gets is called twice.
Incidentally, a plain gets is not the same as STDIN.gets, but is more
like ARGF.gets. It makes a difference when someone puts some arguments
on the command line. Use STDIN.gets to be safe.
Brian C. wrote:
if gets.chomp! == "!quit" then
cleanupAndExit
else
puts gets.chomp!
end
Note how gets is called twice.
Also, I have a question…
results = select([@sock, STDIN], nil, nil)
for input in results[0]
[...]
end #for
end #if
Instead of doing a for loop - just do “results[0].each”, which is more
idiomatic.
The question is, what does “select” do ? rdocs aren’t helpful, and I
don’t understand that bit of code.
Brian C.:
Incidentally, a plain gets is not the same as STDIN.gets, but is
more like ARGF.gets. It makes a difference when someone puts some
arguments on the command line. Use STDIN.gets to be safe.
Or, better yet, use $stdin.gets – IMHO in general it’s better to use the
global variables ($stdin, $stdout, $stderr) rather than the constants
(STDIN, STDOUT, STDERR), because you can repoint the variables as you
see fit without generating a Ruby warning.
For example, when specing my ‘executable’ classes with RSpec,
I often want to specify that something should show up on the
standard error, and I usually do something like this:
module Signore describe Executable do
before do
@orig_stderr = $stderr
$stderr = StringIO.new
end
after do
$stderr = @orig_stderr
end
def stderr
$stderr.rewind
$stderr.read
end
it ‘should print usage if no command was given’ do
lambda { Executable.new([]) }.should raise_error SystemExit
stderr.should match /usage: signore prego|pronto [label, …]/
end
…
end end
— Shot
On 20.11.2009 18:14, Aldric G. wrote:
results = select([@sock, STDIN], nil, nil)
for input in results[0]
[...]
end #for
end #if
Instead of doing a for loop - just do “results[0].each”, which is more
idiomatic.
Absolutely. Usually one would do
ios = [… ]
in, = select(ios)
in.each do |io|
data = io.read_nonblock 1024
…
end
The question is, what does “select” do ? rdocs aren’t helpful, and I
don’t understand that bit of code.
See Brian’s explanation.
Kind regards
robert
Aldric G. wrote:
The question is, what does “select” do ? rdocs aren’t helpful, and I
don’t understand that bit of code.
You’re right, “ri Kernel#select” and “ri IO::select” are both extremely
poor.
But it’s essentially the same as the C “select” call, which you can read
about using “man 2 select” if you have the right manpages installed
(under Ubuntu: sudo apt-get manpages-dev)
It checks a number of IO descriptors for readiness for reading, writing
or exceptional conditions, and returns when at least one of them is
ready or a timeout has expired.
select([@sock, STDIN], nil, nil)
has no timeout parameter so will wait indefinitely. Only read_fds are
specified, so it will return an array containing either @sock or STDIN
or both, depending on which of them has data to read.