Class: RubyExpect::Expect
- Inherits:
-
Object
- Object
- RubyExpect::Expect
- Defined in:
- lib/ruby_expect/expect.rb
Overview
This is the main class used to interact with IO objects An Expect object can be used to send and receive data on any read/write IO object.
Instance Attribute Summary collapse
-
#before ⇒ Object
readonly
Any data that was in the accumulator buffer before match in the last expect call if the last call to expect resulted in a timeout, then before is an empty string.
-
#buffer ⇒ Object
readonly
The accumulator buffer populated by read_loop.
-
#debug ⇒ Object
Set debug in order to see the output being read from the spawned process.
-
#last_match ⇒ Object
readonly
The MatchData object from the last expect call or nil upon a timeout.
-
#match ⇒ Object
readonly
The exact string that matched in the last expect call.
Class Method Summary collapse
-
.connect(socket, options = {}, &block) ⇒ Object
Connect to a socket.
-
.spawn(command, options = {}, &block) ⇒ Object
Spawn a command and interact with it.
Instance Method Summary collapse
-
#expect(*patterns, &block) ⇒ Object
Wait until either the timeout occurs or one of the given patterns is seen in the input.
-
#initialize(*args, &block) ⇒ Expect
constructor
Create a new Expect object for the given IO object.
-
#interact ⇒ Object
Provides the ability to hand control back to the user and allow them to interact with the spawned process.
-
#procedure(&block) ⇒ Object
Perform a series of ‘expects’ using the DSL defined in Procedure.
-
#send(command) ⇒ Object
Convenience method that will send a string followed by a newline to the write handle of the IO object.
-
#soft_close ⇒ Object
Wait for the process to complete or the read handle to be closed and then clean everything up.
-
#timeout ⇒ Object
Get the current timeout value.
-
#timeout=(timeout) ⇒ Object
Set the time to wait for an expected pattern.
Constructor Details
#initialize(*args, &block) ⇒ Expect
Create a new Expect object for the given IO object
There are two ways to create a new Expect object. The first is to supply a single IO object with a read/write mode. The second method is to supply a read file handle as the first argument and a write file handle as the second argument.
args-
at most 3 arguments, 1 or 2 IO objects (read/write or read + write and an optional options hash. The only currently supported option is :debug (default false) which, if enabled, will send data received on the input filehandle to STDOUT
block-
An optional block called upon initialization. See procedure
Examples
# expect with a read/write filehandle
exp = Expect.new(rwfh)
# expect with separate read and write filehandles
exp = Expect.new(rfh, wfh)
# turning on debugging
exp = Expect.new(rfh, wfh, :debug => true)
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/ruby_expect/expect.rb', line 76 def initialize *args, &block = {} if (args.last.is_a?(Hash)) = args.pop end raise ArgumentError("First argument must be an IO object") unless (args[0].is_a?(IO)) if (args.size == 1) @write_fh = args.shift @read_fh = @write_fh elsif (args.size == 2) raise ArgumentError("Second argument must be an IO object") unless (args[1].is_a?(IO)) @write_fh = args.shift @read_fh = args.shift else raise ArgumentError.new("either specify a read/write IO object, or a read IO object and a write IO object") end raise "Input file handle is not readable!" unless (@read_fh.stat.readable?) raise "Output file handle is not writable!" unless (@write_fh.stat.writable?) @child_pid = [:child_pid] @debug = [:debug] || false @buffer = '' @before = '' @match = '' @timeout = 0 unless (block.nil?) procedure(&block) end end |
Instance Attribute Details
#before ⇒ Object (readonly)
Any data that was in the accumulator buffer before match in the last expect call if the last call to expect resulted in a timeout, then before is an empty string
33 34 35 |
# File 'lib/ruby_expect/expect.rb', line 33 def before @before end |
#buffer ⇒ Object (readonly)
The accumulator buffer populated by read_loop. Only access this if you really know what you are doing!
43 44 45 |
# File 'lib/ruby_expect/expect.rb', line 43 def buffer @buffer end |
#debug ⇒ Object
Set debug in order to see the output being read from the spawned process
46 47 48 |
# File 'lib/ruby_expect/expect.rb', line 46 def debug @debug end |
#last_match ⇒ Object (readonly)
The MatchData object from the last expect call or nil upon a timeout
39 40 41 |
# File 'lib/ruby_expect/expect.rb', line 39 def last_match @last_match end |
#match ⇒ Object (readonly)
The exact string that matched in the last expect call
36 37 38 |
# File 'lib/ruby_expect/expect.rb', line 36 def match @match end |
Class Method Details
.connect(socket, options = {}, &block) ⇒ Object
Connect to a socket
command-
The socket or file to connect to
block-
Optional block to call and run a procedure in
134 135 136 137 138 139 140 141 142 143 |
# File 'lib/ruby_expect/expect.rb', line 134 def self.connect socket, = {}, &block require 'socket' client = nil if (socket.is_a?(UNIXSocket)) client = socket else client = UNIXSocket.new(socket) end return RubyExpect::Expect.new(client, , &block) end |
.spawn(command, options = {}, &block) ⇒ Object
Spawn a command and interact with it
command-
The command to execute
block-
Optional block to call and run a procedure in
118 119 120 121 122 |
# File 'lib/ruby_expect/expect.rb', line 118 def self.spawn command, = {}, &block shell_in, shell_out, pid = PTY.spawn(command) [:child_pid] = pid return RubyExpect::Expect.new(shell_out, shell_in, , &block) end |
Instance Method Details
#expect(*patterns, &block) ⇒ Object
Wait until either the timeout occurs or one of the given patterns is seen in the input. Upon a match, the property before is assigned all input in the accumulator before the match, the matched string itself is assigned to the match property and an optional block is called
The method will return the index of the matched pattern or nil if no match has occurred during the timeout period
patterns-
list of patterns to look for. These can be either literal strings or Regexp objects
block-
An optional block to be called if one of the patterns matches
Example
exp = Expect.new(io)
exp.expect('Password:') do
send("12345")
end
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/ruby_expect/expect.rb', line 230 def expect *patterns, &block patterns = pattern_escape(*patterns) @end_time = 0 if (@timeout != 0) @end_time = Time.now + @timeout end @before = '' matched_index = nil while (@end_time == 0 || Time.now < @end_time) return nil if (@read_fh.closed?) break unless (read_proc) @last_match = nil patterns.each_index do |i| if (match = patterns[i].match(@buffer)) @last_match = match @before = @buffer.slice!(0...match.begin(0)) @match = @buffer.slice!(0...match.to_s.length) matched_index = i break end end unless (@last_match.nil?) unless (block.nil?) instance_eval(&block) end return matched_index end end return nil end |
#interact ⇒ Object
Provides the ability to hand control back to the user and allow them to interact with the spawned process.
283 284 285 286 287 288 289 290 291 |
# File 'lib/ruby_expect/expect.rb', line 283 def interact if ($stdin.tty?) $stdin.raw do |stdin| interact_loop(stdin) end else interact_loop($stdin) end end |
#procedure(&block) ⇒ Object
Perform a series of ‘expects’ using the DSL defined in Procedure
block-
The block will be called in the context of a new Procedure object
Example
exp = Expect.new(io)
exp.procedure do
each do
expect /first expected line/ do
send "some text to send"
end
expect /second expected line/ do
send "some more text to send"
end
end
end
166 167 168 |
# File 'lib/ruby_expect/expect.rb', line 166 def procedure &block RubyExpect::Procedure.new(self, &block) end |
#send(command) ⇒ Object
Convenience method that will send a string followed by a newline to the write handle of the IO object
command-
String to send down the pipe
203 204 205 |
# File 'lib/ruby_expect/expect.rb', line 203 def send command @write_fh.write("#{command}\n") end |
#soft_close ⇒ Object
Wait for the process to complete or the read handle to be closed and then clean everything up. This method call will block until the spawned process or connected filehandle/socket is closed
267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/ruby_expect/expect.rb', line 267 def soft_close while (! @read_fh.closed?) read_proc end @read_fh.close unless (@read_fh.closed?) @write_fh.close unless (@write_fh.closed?) if (@child_pid) Process.wait(@child_pid) return $? end return true end |
#timeout ⇒ Object
Get the current timeout value
192 193 194 |
# File 'lib/ruby_expect/expect.rb', line 192 def timeout @timeout end |
#timeout=(timeout) ⇒ Object
Set the time to wait for an expected pattern
timeout-
number of seconds to wait before giving up. A value of zero means wait forever
177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/ruby_expect/expect.rb', line 177 def timeout= timeout unless (timeout.is_a?(Integer)) raise "Timeout must be an integer" end unless (timeout >= 0) raise "Timeout must be greater than or equal to zero" end @timeout = timeout @end_time = 0 end |