title: ruby popen3 -- how to repeatedly write to stdin & read stdout without re-opening process?
body: <p>I am using <a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/open3/rdoc/Open3.html" rel="noreferrer">Open3</a>'s <a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/open3/rdoc/Open3.html#method-c-popen3" rel="noreferrer">popen3</a> method to start a process that functions in a console-like / <a href="http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noreferrer">REPL</a> fashion to repeatedly accept input and return output.</p>
  
  <p>I am able to open the process, send input, and receive the output just fine, with code like this:</p>
  
  <pre><code>Open3.popen3("console_REPL_process") do |stdin, stdout, stderr, wait_thr|
      stdin.puts "a string of input"
      stdin.close_write
      stdout.each_line { |line| puts line } #successfully prints all the output
  end
  </code></pre>
  
  <p>I want to do that many times in a row, without re-opening the process, as it takes a long time to start up. </p>
  
  <p>I know I have to close stdin in order for stdout to return.. but what I don't know is, <strong>how do I 'reopen' stdin so I can write more input?</strong></p>
  
  <p>Ideally I want to do something like this:</p>
  
  <pre><code>Open3.popen3("console_REPL_process") do |stdin, stdout, stderr, wait_thr|
      stdin.puts "a string of input"
      stdin.close_write
      stdout.each_line { |line| puts line }
  
      stdin.reopen_somehow()
  
      stdin.puts "another string of input"
      stdin.close_write
      stdout.each_line { |line| puts line }
      # etc..
  end
  </code></pre>
  
  <h1>solution</h1>
  
  <p>Thanks to pmoo's answer, I was able to devise a solution using <code>PTY</code> and <code>expect</code>, expecting the prompt string that the process returns whenever it is ready for more input, like so:</p>
  
  <pre><code>PTY.spawn("console_REPL_process") do |output, input|
      output.expect("prompt &gt;") do |result|
        input.puts "string of input"
      end
      output.expect("prompt &gt;") do |result|
        puts result
        input.puts "another string of input"
      end
      output.expect("prompt &gt;") do |result|
        puts result
        input.puts "a third string of input"
      end
      # and so forth
  end
  </code></pre>