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.
-
#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)
75 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 |
# File 'lib/ruby_expect/expect.rb', line 75 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
32 33 34 |
# File 'lib/ruby_expect/expect.rb', line 32 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!
42 43 44 |
# File 'lib/ruby_expect/expect.rb', line 42 def buffer @buffer end |
#debug ⇒ Object
Set debug in order to see the output being read from the spawned process
45 46 47 |
# File 'lib/ruby_expect/expect.rb', line 45 def debug @debug end |
#last_match ⇒ Object (readonly)
The MatchData object from the last expect call or nil upon a timeout
38 39 40 |
# File 'lib/ruby_expect/expect.rb', line 38 def last_match @last_match end |
#match ⇒ Object (readonly)
The exact string that matched in the last expect call
35 36 37 |
# File 'lib/ruby_expect/expect.rb', line 35 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
133 134 135 136 137 138 139 140 141 142 |
# File 'lib/ruby_expect/expect.rb', line 133 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
117 118 119 120 121 |
# File 'lib/ruby_expect/expect.rb', line 117 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
229 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 |
# File 'lib/ruby_expect/expect.rb', line 229 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 |
#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
165 166 167 |
# File 'lib/ruby_expect/expect.rb', line 165 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
202 203 204 |
# File 'lib/ruby_expect/expect.rb', line 202 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
266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/ruby_expect/expect.rb', line 266 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
191 192 193 |
# File 'lib/ruby_expect/expect.rb', line 191 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
176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/ruby_expect/expect.rb', line 176 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 |