IO stream help


#1

I am struggling with handling stdin and stdout in Ruby.

A java application I have responds works as a helper for an external
application by doing the following:

in = new BufferedReader(new InputStreamReader(System.in));
out = new PrintStream(System.out, true);

while((stream = in.readLine()).length() != 0) {

}

How can this be done in Ruby?

Any help would be grealy appreciated.


#2

Something like this?

irb(main):007:0> while (!(input=$stdin.readline.chomp).length.zero?)
irb(main):008:1> puts input
irb(main):009:1> end
Hello
Hello
World
World

=> nil


#3

Farrel L. wrote:

Something like this?

irb(main):007:0> while (!(input=$stdin.readline.chomp).length.zero?)
irb(main):008:1> puts input
irb(main):009:1> end
Hello
Hello
World
World

=> nil

Thank. But no luck.

It seems to hang waiting for input.


#4

On Apr 13, 2006, at 11:46 AM, Lon B. wrote:

=> nil

Thank. But no luck.

It seems to hang waiting for input.

And you don’t want it to block for input? Are you trying to use
asynchronous IO or something?


#5

On Fri, 14 Apr 2006, Lon B. wrote:

Would IO.popen or pipe be something to look at?
you need something like

Thread.new(cmd) do |cmd|
IO.popen(cmd, ‘r+’) do |pipe|
pipe.each do |line|
case line
when /request a/
pipe.puts ‘response a’
when /request b/
pipe.puts ‘response b’
end
end
end
end

… do other stuff while thread runs

if you don’t have ‘other stuff’ to do there’s no point in making it
async of
course though…

regards.

-a


#6

Logan C. wrote:

On Apr 13, 2006, at 11:46 AM, Lon B. wrote:

=> nil

Thank. But no luck.

It seems to hang waiting for input.

And you don’t want it to block for input? Are you trying to use
asynchronous IO or something?

Yes it needs to be asynchronous.

The application is listening and responding to an external application.

It sits there listening for commands, processes them and responds with
its own commands.

Would IO.popen or pipe be something to look at?


#7

Thanks for all the help.

I came up with the following code that works.

run = true

$stdout.sync = true

while run
input,output,error = IO::select( [$stdin], nil, nil, nil )
(input||[]).each {|s|
chunks = s.readline.split
case chunks[1]
when /INTF/
$stdout.puts “#{chunks[0]} #{chunks[1]} #{chunks[2]}”
when /QUIT/
$stdout.puts “#{chunks[0]} OK”
run = false
else
$stdout.puts “#{chunks[0]} OK”
end
}
end

This is used in a helper application for Communigate Pro mail servers.


#8

Thank you! I did not realize that is what I had done.

The reason the previous suggested solution did not work, is that the
ruby script is not issuing a command, but is only responding to an
external process.

I thought this:

Thread.new(cmd) do |cmd|
IO.popen(cmd, ‘r+’) do |pipe|

Issued a command to the system.

Where my needs are for a script that is launched by and controlled by
the mail server.

Here is what happens with the mail server.

It issues commands in the following format:

109 FILE Queue/190016.msg\n

The number is the thread of communication, all requests and responses
start with this to tell the mail server what thread of communication it
is dealing with.

Its followed by a command, in this example “FILE”, which is followed by
the argument being the path to a file.

The server issues a request for each thread while waiting for the
responses, but will never issue a new request for a previously requested
thread.

Thanks again for the help. I will go back to the drawing board.


#9

On Fri, 14 Apr 2006, Lon B. wrote:

(input||[]).each {|s|
}
end

This is used in a helper application for Communigate Pro mail servers.

but this is blocking? we thought you were needing asynchronous code?
what
you’ve written above will behave exactly like

STDOUT.sync = true

STDIN.each do |s|
chunks = s.readline.split
case chunks[1]
when /INTF/
puts “#{chunks[0]} #{chunks[1]} #{chunks[2]}”
when /QUIT/
puts “#{chunks[0]} OK”
else
puts “#{chunks[0]} OK”
end
end

that’s because what you’ve got above does this

here we block until io is ready to read. note that this can be

because

there is one char available or eof.

 input,output,error = IO::select( [$stdin], nil, nil, nil )

here we block until a newline is read. note that a newline may

never be

read, or may take a very long time to arrive. esp if the

co-process is

buffering io. and that’s for the first iteration of the loop. on

the

second iteration this loop degrades into a ‘normally’ blocking call

(note

that select is not called again).

 (input||[]).each {|s|

in otherwords what you’ve written is a compilcated way to do this

block until io ready. then block until a newline is read.

 gets

not trying to be critical, but after reading your original posts the
above
left me confused. is there some other thread doing some work that must
procedd that’s not being shown?

regards.

-a