Original from RubyGarden
#!/usr/bin/ruby # # $Id$ # # RExpect.rb # require 'pty' require 'thread' require 'timeout' $expect_verbose = true Thread.abort_on_exception = true class RExpect attr_reader :pid def RExpect.spawn(cmd) mutex = Mutex.new mutex.synchronize do resultResource = ConditionVariable.new result = nil Thread.new do pid = nil mutex.synchronize do inf, outf, pid, fileName = PTY.spawn(cmd) result = RExpect.new( inf, outf, pid, fileName) resultResource.signal end result.inputData end resultResource.wait( mutex) return result end end def log(a) @log.puts "#{caller(1)[0]}:#{a}" unless @log.nil? end def initialize(inf,outf,pid,fileName) @inf,@outf,@pid,@fileName = inf,outf,pid,fileName if $expect_verbose then @log = File.open( "rexpect.log.#{@pid}", "w") @log.sync = true else @log = nil end @outf.sync=true @buffer = '' @mutex = Mutex.new @bufferResource = ConditionVariable.new end def wait Process.waitpid(@pid,0) rescue end def kill kill( "SIGTERM", @pid) wait end def inputData while true data = @inf.sysread( 65536) @mutex.synchronize do log( "BUFFER:#{@buffer}\nNEWDATA:#{data}" ) @buffer << data # Alternately: if !@e_pat.nil? && (md = @e_pat.match(@buffer)) if !@e_pat.nil? && @buffer =~ @e_pat then # Alternately (if using the above) @result = [@buffer, *md.to_a[1 .. -1]] @result = [@buffer,$1,$2,$3,$4,$5,$6,$7,$8,$9] @buffer = $' log( "Buffer matched#{@e_pat.source}") @e_pat = nil @bufferResource.signal end end end rescue SystemCallError, EOFError => details log( details) log( details.backtrace.join("\n")) @mutex.synchronize do @bufferResource.signal end rescue RuntimeError => details raise details if details.to_s !~ /Child_changed/ ensure @log.close end def expect(pat,time_out=5) @result = nil @mutex.synchronize do case pat when String @e_pat = Regexp.new(Regexp.quote(pat)) when Regexp @e_pat = pat end log( @e_pat.source) if @buffer =~ @e_pat then @result = [@buffer,$1,$2,$3,$4,$5,$6,$7,$8,$9] @buffer = $' log( "Existing buffer matched#{@e_pat.source}") @e_pat = nil return @result end timeout( time_out) do @bufferResource.wait( @mutex) raise EOFError if @result.nil? end end return @result end def puts(str) log( str) @outf.puts str end end if (__FILE__ == $0) # # Here is a silly example.... # $log = File.open( "hello.log", "w") $me = RExpect.new( STDIN, STDOUT, Process.ppid, "stdio") Thread.new do # Note this _must_ run in its own thread! # Spawn creates its own thread to do this... $me.inputData end def try( pat) $log.puts "Seeking:#{pat.source}" result = $me.expect( pat, 6) $log.puts "Found:#{result}" return result end def say( s) $log.puts "Say: #{s}" $me.puts s end say "Hello world" say "Expecting me?" try( /You again!/) say "Ah well, since you're here, whats your name then?" result = try( /[\n\r]([^\n\r]+)/) if result.nil? then say "Cat got your tongue?" else if result[1] =~ /John/ then say "Not you again" else say "Please to meet you" end end try( /Go away!/) say "Will do" $log.puts "Exiting" $log.close end