IO.popen with Threads

Hi everyone,

I am trying to use IO.popen in order to put and get messages from a
process to its sub-process (according to
http://ruby-doc.org/core/classes/IO.html#M002242).

I am not experimented and I have two questions about:

1/ Do threads are a good choice, for read and write at the same time
(with IO.popen)?
Have you got a simple exemple?

2/ I think IO.popen is useful for asynchrone communication. But when I
just need to send a message from a process to its sub-process, and wait
its answer, how should we do it? (any example is very appreciated)

Many thanks

···

--
Posted via http://www.ruby-forum.com/.

On 01.03.2010 21:51, Eikichi On wrote:

Hi everyone,

I am trying to use IO.popen in order to put and get messages from a
process to its sub-process (according to
class IO - RDoc Documentation).

I am not experimented and I have two questions about:

1/ Do threads are a good choice, for read and write at the same time
(with IO.popen)?

Yes.

Have you got a simple exemple?

Please see answer to second question.

2/ I think IO.popen is useful for asynchrone communication. But when I
just need to send a message from a process to its sub-process, and wait
its answer, how should we do it? (any example is very appreciated)

reply = IO.popen ["cat", "-n"], "r+" do |io|
   rdr = Thread.new { io.read } # alternative: io.readlines
   io.puts "message", "you", "want to send"
   io.close_write

   rdr.value # joins and fetches the result
end

Kind regards

  robert

···

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thank you very much for your answer, Robert. Thanks to your help, I
could start coding. But I have another little problem and I would
appreciate your opinion.

Here is the code I used:

    class Test
      def initialize(program)
        while isready?(program) && cool?(program)
          program.puts 'start', 'my name is ...'
          # ...
        end
      end

      protected

      def process_command(program, command)
        begin
          rdr = Thread.new { program.read } # alternative: io.readlines
          program.puts "#{command}"
          program.close_write
          rdr.value # joins and fetches the result
        end
      end

      def isready?(program)
        reply = process_command(program, 'isready')
        reply.chomp.match(/yes_i_am_ready$/)
      end

      def cool?(program)
        reply = process_command(program, 'cool')
        reply.chomp.match(/yes_i_am_cool$/)
      end
    end

program = IO.popen("./program", "w+")

a = Test.new(program)
(...)in `write': not opened for writing (IOError)

As we can see, there is an error when I try to send a message to the
sub-process because of the closure of the stream
(http://ruby-doc.org/core/classes/IO.html#M002289).

I believe that it is not possible to open again a closed stream. Do you
think a good way is to don't close the stream (except at the very end of
the Ruby script)? or should it be better to change the current code
structure?

Thanks again for any help.

···

--
Posted via http://www.ruby-forum.com/.

Thank you very much for your answer, Robert. Thanks to your help, I
could start coding. But I have another little problem and I would
appreciate your opinion.

Here is the code I used:

class Test
def initialize(program)
while isready?(program) && cool?(program)
program.puts 'start', 'my name is ...'
# ...
end
end

 protected

 def process\_command\(program, command\)
   begin
     rdr = Thread\.new \{ program\.read \} \# alternative: io\.readlines
     program\.puts "\#\{command\}"
     program\.close\_write
     rdr\.value \# joins and fetches the result
   end
 end

 def isready?\(program\)
   reply = process\_command\(program, 'isready'\)
   reply\.chomp\.match\(/yes\_i\_am\_ready$/\)
 end

 def cool?\(program\)
   reply = process\_command\(program, 'cool'\)
   reply\.chomp\.match\(/yes\_i\_am\_cool$/\)
 end

end

program = IO.popen("./program", "w+")

a = Test.new(program)
(...)in `write': not opened for writing (IOError)

As we can see, there is an error when I try to send a message to the
sub-process because of the closure of the stream
(class IO - RDoc Documentation).

I believe that it is not possible to open again a closed stream.

Exactly that is the source of your error.

Do you
think a good way is to don't close the stream (except at the very end of
the Ruby script)? or should it be better to change the current code
structure?

I would certainly change the structure. I would put the IO.popen
inside the class since you will be writing a class handling a specific
external program - at least that's what seems to be the case here.

When you close the stream depends on the external program you are
executing. There is no general rule I can give you here.

Note that if you need to deal with multiple requests and responses
from the external process I believe there are a number of tools around
for that already. You should be able to find something by searching
for "ruby expect".

Kind regards

robert

···

2010/3/2 Eikichi On <eikichi@ymail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thank you for your reply very educational, very clear. I have tested
IO#readline instead of IO#read, but once again I've got a "write" error.
And I don't exactly see how to fix it.

I just would like to establish a such communication (according to a
given protocol) like:

Parent message: Child answer:
-------------- ------------

'are u ready?' 'yes_i_am_ready'
'are u cool?' 'yes_i_am_cool'
'Hello' 'foo'
'my name is ...' 'bar'

Help me please :o

···

--
Posted via http://www.ruby-forum.com/.

That's exactly the "expect" like model. See for example:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/66884

Kind regards

robert

···

2010/3/2 Eikichi On <eikichi@ymail.com>:

Thank you for your reply very educational, very clear. I have tested
IO#readline instead of IO#read, but once again I've got a "write" error.
And I don't exactly see how to fix it.

I just would like to establish a such communication (according to a
given protocol) like:

Parent message: Child answer:
-------------- ------------

'are u ready?' 'yes_i_am_ready'
'are u cool?' 'yes_i_am_cool'
'Hello' 'foo'
'my name is ...' 'bar'

Help me please :o

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/