Ruby expect alternative, responding to commandline interfaces

A small snippet to interact with commandline applications that ask questions on stdin, particularly useful for testing.

Usage

interact "rails new foo -m template.rb", /RSpec/ => 'y', /MySql/ => 'n'

Code

 # https://gist.github.com/2166521
 # capture commandline output and send responses if nothing was read
  def interact(command, answers)
    puts command
    line = ""
    write = false

    PTY.spawn(command) do |output, input, pid|
      loop do
        rs, ws, = IO.select([output], [input])

        # read into the buffer
        if r = rs[0]
          write = false
          ret = r.read(1)
          print ret

          return unless ret

          line << ret
          line = "" if ret == "\n"
        end

        # time to write ?
        if w = ws[0]
          if write and line != ""
            text = line.gsub(/\e\[\d+m/,'').strip
            answer = answers.detect do |question, answer|
              text =~ question
            end || raise("Question #{text.inspect} has no answer!")
            w.write(answer.last + "\n")
            line = ""
          else
            write = true
          end
        end
      end
    end
    $?.success?
  end

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s