ruby_expect 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/ruby_expect.rb +16 -0
- data/lib/ruby_expect/expect.rb +342 -0
- data/lib/ruby_expect/procedure.rb +179 -0
- metadata +66 -0
data/lib/ruby_expect.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#####
|
|
2
|
+
# = LICENSE
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2012 Andrew Bates Licensed under the Apache License, Version 2.0
|
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
|
6
|
+
# License. You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
# License for the specific language governing permissions and limitations under
|
|
14
|
+
# the License.
|
|
15
|
+
#
|
|
16
|
+
require 'ruby_expect/expect'
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
#####
|
|
2
|
+
# = LICENSE
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2012 Andrew Bates Licensed under the Apache License, Version 2.0
|
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
|
6
|
+
# License. You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
# License for the specific language governing permissions and limitations under
|
|
14
|
+
# the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
require 'thread'
|
|
18
|
+
require 'ruby_expect/procedure'
|
|
19
|
+
require 'pty'
|
|
20
|
+
|
|
21
|
+
#####
|
|
22
|
+
#
|
|
23
|
+
#
|
|
24
|
+
module RubyExpect
|
|
25
|
+
#####
|
|
26
|
+
# This is the main class used to interact with IO objects An Expect object can
|
|
27
|
+
# be used to send and receive data on any read/write IO object.
|
|
28
|
+
#
|
|
29
|
+
class Expect
|
|
30
|
+
# Any data that was in the accumulator buffer before match in the last expect call
|
|
31
|
+
# if the last call to expect resulted in a timeout, then before is an empty string
|
|
32
|
+
attr_reader :before
|
|
33
|
+
|
|
34
|
+
# The exact string that matched in the last expect call
|
|
35
|
+
attr_reader :match
|
|
36
|
+
|
|
37
|
+
# The MatchData object from the last expect call or nil upon a timeout
|
|
38
|
+
attr_reader :last_match
|
|
39
|
+
|
|
40
|
+
# The accumulator buffer populated by read_loop. Only access this if you really
|
|
41
|
+
# know what you are doing!
|
|
42
|
+
attr_reader :buffer
|
|
43
|
+
|
|
44
|
+
#####
|
|
45
|
+
# Create a new Expect object for the given IO object
|
|
46
|
+
#
|
|
47
|
+
# There are two ways to create a new Expect object. The first is to supply
|
|
48
|
+
# a single IO object with a read/write mode. The second method is to supply
|
|
49
|
+
# a read file handle as the first argument and a write file handle as the
|
|
50
|
+
# second argument.
|
|
51
|
+
#
|
|
52
|
+
# +args+::
|
|
53
|
+
# at most 3 arguments, 1 or 2 IO objects (read/write or read + write and
|
|
54
|
+
# an optional options hash. The only currently supported option is :debug
|
|
55
|
+
# (default false) which, if enabled, will send data received on the input
|
|
56
|
+
# filehandle to STDOUT
|
|
57
|
+
#
|
|
58
|
+
# +block+::
|
|
59
|
+
# An optional block called upon initialization. See procedure
|
|
60
|
+
#
|
|
61
|
+
# == Examples
|
|
62
|
+
#
|
|
63
|
+
# # expect with a read/write filehandle
|
|
64
|
+
# exp = Expect.new(rwfh)
|
|
65
|
+
#
|
|
66
|
+
# # expect with separate read and write filehandles
|
|
67
|
+
# exp = Expect.new(rfh, wfh)
|
|
68
|
+
#
|
|
69
|
+
# # turning on debugging
|
|
70
|
+
# exp = Expect.new(rfh, wfh, :debug => true)
|
|
71
|
+
#
|
|
72
|
+
def initialize *args, &block
|
|
73
|
+
options = {}
|
|
74
|
+
if (args.last.is_a?(Hash))
|
|
75
|
+
options = args.pop
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
raise ArgumentError("First argument must be an IO object") unless (args[0].is_a?(IO))
|
|
79
|
+
if (args.size == 1)
|
|
80
|
+
@write_fh = args.shift
|
|
81
|
+
@read_fh = @write_fh
|
|
82
|
+
elsif (args.size == 2)
|
|
83
|
+
raise ArgumentError("Second argument must be an IO object") unless (args[1].is_a?(IO))
|
|
84
|
+
@write_fh = args.shift
|
|
85
|
+
@read_fh = args.shift
|
|
86
|
+
else
|
|
87
|
+
raise ArgumentError.new("either specify a read/write IO object, or a read IO object and a write IO object")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
raise "Input file handle is not readable!" unless (@read_fh.stat.readable?)
|
|
91
|
+
raise "Output file handle is not writable!" unless (@write_fh.stat.writable?)
|
|
92
|
+
|
|
93
|
+
@buffer_sem = Mutex.new
|
|
94
|
+
@buffer_cv = ConditionVariable.new
|
|
95
|
+
@child_pid = options[:child_pid]
|
|
96
|
+
@debug = options[:debug] || false
|
|
97
|
+
@buffer = ''
|
|
98
|
+
@before = ''
|
|
99
|
+
@match = ''
|
|
100
|
+
@timeout = 0
|
|
101
|
+
|
|
102
|
+
read_loop # start the read thread
|
|
103
|
+
|
|
104
|
+
unless (block.nil?)
|
|
105
|
+
procedure(&block)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
#####
|
|
110
|
+
# Spawn a command and interact with it
|
|
111
|
+
#
|
|
112
|
+
# +command+::
|
|
113
|
+
# The command to execute
|
|
114
|
+
#
|
|
115
|
+
# +block+::
|
|
116
|
+
# Optional block to call and run a procedure in
|
|
117
|
+
#
|
|
118
|
+
def self.spawn command, options = {}, &block
|
|
119
|
+
shell_in, shell_out, pid = PTY.spawn(command)
|
|
120
|
+
options[:child_pid] = pid
|
|
121
|
+
return RubyExpect::Expect.new(shell_out, shell_in, options, &block)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
#####
|
|
126
|
+
# Connect to a socket
|
|
127
|
+
#
|
|
128
|
+
# +command+::
|
|
129
|
+
# The socket or file to connect to
|
|
130
|
+
#
|
|
131
|
+
# +block+::
|
|
132
|
+
# Optional block to call and run a procedure in
|
|
133
|
+
#
|
|
134
|
+
def self.connect socket, options = {}, &block
|
|
135
|
+
require 'socket'
|
|
136
|
+
client = nil
|
|
137
|
+
if (socket.is_a?(UNIXSocket))
|
|
138
|
+
client = socket
|
|
139
|
+
else
|
|
140
|
+
client = UNIXSocket.new(socket)
|
|
141
|
+
end
|
|
142
|
+
return RubyExpect::Expect.new(client, options, &block)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
#####
|
|
146
|
+
# Perform a series of 'expects' using the DSL defined in Procedure
|
|
147
|
+
#
|
|
148
|
+
# +block+::
|
|
149
|
+
# The block will be called in the context of a new Procedure object
|
|
150
|
+
#
|
|
151
|
+
# == Example
|
|
152
|
+
#
|
|
153
|
+
# exp = Expect.new(io)
|
|
154
|
+
# exp.procedure do
|
|
155
|
+
# each do
|
|
156
|
+
# expect /first expected line/ do
|
|
157
|
+
# send "some text to send"
|
|
158
|
+
# end
|
|
159
|
+
#
|
|
160
|
+
# expect /second expected line/ do
|
|
161
|
+
# send "some more text to send"
|
|
162
|
+
# end
|
|
163
|
+
# end
|
|
164
|
+
# end
|
|
165
|
+
#
|
|
166
|
+
def procedure &block
|
|
167
|
+
RubyExpect::Procedure.new(self, &block)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
#####
|
|
171
|
+
# Set the time to wait for an expected pattern
|
|
172
|
+
#
|
|
173
|
+
# +timeout+::
|
|
174
|
+
# number of seconds to wait before giving up. A value of zero means wait
|
|
175
|
+
# forever
|
|
176
|
+
#
|
|
177
|
+
def timeout= timeout
|
|
178
|
+
unless (timeout.is_a?(Integer))
|
|
179
|
+
raise "Timeout must be an integer"
|
|
180
|
+
end
|
|
181
|
+
unless (timeout >= 0)
|
|
182
|
+
raise "Timeout must be greater than or equal to zero"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
@timeout = timeout
|
|
186
|
+
@end_time = 0
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
####
|
|
190
|
+
# Get the current timeout value
|
|
191
|
+
#
|
|
192
|
+
def timeout
|
|
193
|
+
@timeout
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
#####
|
|
197
|
+
# Convenience method that will send a string followed by a newline to the
|
|
198
|
+
# write handle of the IO object
|
|
199
|
+
#
|
|
200
|
+
# +command+::
|
|
201
|
+
# String to send down the pipe
|
|
202
|
+
#
|
|
203
|
+
def send command
|
|
204
|
+
@write_fh.write("#{command}\n")
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
#####
|
|
208
|
+
# Wait until either the timeout occurs or one of the given patterns is seen
|
|
209
|
+
# in the input. Upon a match, the property before is assigned all input in
|
|
210
|
+
# the accumulator before the match, the matched string itself is assigned to
|
|
211
|
+
# the match property and an optional block is called
|
|
212
|
+
#
|
|
213
|
+
# The method will return the index of the matched pattern or nil if no match
|
|
214
|
+
# has occurred during the timeout period
|
|
215
|
+
#
|
|
216
|
+
# +patterns+::
|
|
217
|
+
# list of patterns to look for. These can be either literal strings or
|
|
218
|
+
# Regexp objects
|
|
219
|
+
#
|
|
220
|
+
# +block+::
|
|
221
|
+
# An optional block to be called if one of the patterns matches
|
|
222
|
+
#
|
|
223
|
+
# == Example
|
|
224
|
+
#
|
|
225
|
+
# exp = Expect.new(io)
|
|
226
|
+
# exp.expect('Password:') do
|
|
227
|
+
# send("12345")
|
|
228
|
+
# end
|
|
229
|
+
#
|
|
230
|
+
def expect *patterns, &block
|
|
231
|
+
patterns = pattern_escape(*patterns)
|
|
232
|
+
@end_time = 0
|
|
233
|
+
if (@timeout != 0)
|
|
234
|
+
@end_time = Time.now + @timeout
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
@before = ''
|
|
238
|
+
matched_index = nil
|
|
239
|
+
while (@end_time == 0 || Time.now < @end_time)
|
|
240
|
+
return nil if (@read_fh.closed?)
|
|
241
|
+
@last_match = nil
|
|
242
|
+
@buffer_sem.synchronize do
|
|
243
|
+
patterns.each_index do |i|
|
|
244
|
+
if (match = patterns[i].match(@buffer))
|
|
245
|
+
@last_match = match
|
|
246
|
+
@before = @buffer.slice!(0...match.begin(0))
|
|
247
|
+
@match = @buffer.slice!(0...match.to_s.length)
|
|
248
|
+
matched_index = i
|
|
249
|
+
break
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
@buffer_cv.wait(@buffer_sem) if (@last_match.nil?)
|
|
253
|
+
end
|
|
254
|
+
unless (@last_match.nil?)
|
|
255
|
+
unless (block.nil?)
|
|
256
|
+
instance_eval(&block)
|
|
257
|
+
end
|
|
258
|
+
return matched_index
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
return nil
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def soft_close
|
|
265
|
+
while (! @read_fh.closed?)
|
|
266
|
+
@buffer_sem.synchronize do
|
|
267
|
+
@buffer_cv.wait(@buffer_sem)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
@read_fh.close unless (@read_fh.closed?)
|
|
271
|
+
@write_fh.close unless (@write_fh.closed?)
|
|
272
|
+
if (@child_pid)
|
|
273
|
+
Process.wait(@child_pid)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
private
|
|
278
|
+
#####
|
|
279
|
+
# This method will convert any strings in the argument list to regular
|
|
280
|
+
# expressions that search for the literal string
|
|
281
|
+
#
|
|
282
|
+
# +patterns+::
|
|
283
|
+
# List of patterns to escape
|
|
284
|
+
#
|
|
285
|
+
def pattern_escape *patterns
|
|
286
|
+
escaped_patterns = []
|
|
287
|
+
patterns.each do |pattern|
|
|
288
|
+
if (pattern.is_a?(String))
|
|
289
|
+
pattern = Regexp.new(Regexp.escape(pattern))
|
|
290
|
+
elsif (! pattern.is_a?(Regexp))
|
|
291
|
+
raise "Don't know how to match on a #{pattern.class}"
|
|
292
|
+
end
|
|
293
|
+
escaped_patterns.push(pattern)
|
|
294
|
+
end
|
|
295
|
+
escaped_patterns
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
#####
|
|
299
|
+
# The read loop is an internal method that constantly waits for input to
|
|
300
|
+
# arrive on the IO object. When input arrives it is appended to an
|
|
301
|
+
# internal buffer for use by the expect method
|
|
302
|
+
#
|
|
303
|
+
def read_loop
|
|
304
|
+
Thread.abort_on_exception = true
|
|
305
|
+
Thread.new do
|
|
306
|
+
while (true)
|
|
307
|
+
begin
|
|
308
|
+
ready = IO.select([@read_fh], nil, nil, 1)
|
|
309
|
+
if (ready.nil? || ready.size == 0)
|
|
310
|
+
@buffer_cv.signal()
|
|
311
|
+
else
|
|
312
|
+
if (@read_fh.eof?)
|
|
313
|
+
@read_fh.close
|
|
314
|
+
@buffer_cv.signal()
|
|
315
|
+
break
|
|
316
|
+
else
|
|
317
|
+
input = @read_fh.readpartial(4096)
|
|
318
|
+
@buffer_sem.synchronize do
|
|
319
|
+
@buffer << input
|
|
320
|
+
@buffer_cv.signal()
|
|
321
|
+
end
|
|
322
|
+
if (@debug)
|
|
323
|
+
STDERR.print input
|
|
324
|
+
STDERR.flush
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
rescue EOFError => e
|
|
329
|
+
rescue Exception => e
|
|
330
|
+
unless (e.to_s == 'stream closed')
|
|
331
|
+
STDERR.puts "Exception in read_loop:"
|
|
332
|
+
STDERR.puts "#{e}"
|
|
333
|
+
STDERR.puts "\t#{e.backtrace.join("\n\t")}"
|
|
334
|
+
end
|
|
335
|
+
break
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#####
|
|
2
|
+
# = LICENSE
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2012 Andrew Bates Licensed under the Apache License, Version 2.0
|
|
5
|
+
# (the "License"); you may not use this file except in compliance with the
|
|
6
|
+
# License. You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
# License for the specific language governing permissions and limitations under
|
|
14
|
+
# the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
#####
|
|
18
|
+
#
|
|
19
|
+
#
|
|
20
|
+
module RubyExpect
|
|
21
|
+
#####
|
|
22
|
+
# A pattern is a simple container to hold a string/regexp pattern and proc to
|
|
23
|
+
# be called upon match. This is an internal container used by the Procedure
|
|
24
|
+
# class
|
|
25
|
+
#
|
|
26
|
+
class Pattern
|
|
27
|
+
attr_reader :pattern, :block
|
|
28
|
+
#####
|
|
29
|
+
# +pattern+::
|
|
30
|
+
# String or Regexp objects to match on
|
|
31
|
+
#
|
|
32
|
+
# +block+::
|
|
33
|
+
# The block/proc to be called if a match occurs
|
|
34
|
+
#
|
|
35
|
+
def initialize pattern, &block
|
|
36
|
+
@pattern = pattern
|
|
37
|
+
@block = block
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#####
|
|
42
|
+
# Super class for common methods for AnyMatch and EachMatch
|
|
43
|
+
#
|
|
44
|
+
class Match
|
|
45
|
+
#####
|
|
46
|
+
# +exp_object+::
|
|
47
|
+
# The expect object used for interaction
|
|
48
|
+
#
|
|
49
|
+
# +block+::
|
|
50
|
+
# The block will be called in the context of the initialized match object
|
|
51
|
+
#
|
|
52
|
+
def initialize exp_object, &block
|
|
53
|
+
@exp = exp_object
|
|
54
|
+
@patterns = []
|
|
55
|
+
instance_eval(&block) unless block.nil?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#####
|
|
59
|
+
# Add a pattern to be expected by the process
|
|
60
|
+
#
|
|
61
|
+
# +pattern+::
|
|
62
|
+
# String or Regexp to match on
|
|
63
|
+
#
|
|
64
|
+
# +block+::
|
|
65
|
+
# Block to be called upon a match
|
|
66
|
+
#
|
|
67
|
+
def expect pattern, &block
|
|
68
|
+
@patterns.push(Pattern.new(pattern, &block))
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#####
|
|
73
|
+
# Expect any one of the specified patterns and call the matching pattern's
|
|
74
|
+
# block
|
|
75
|
+
#
|
|
76
|
+
class AnyMatch < Match
|
|
77
|
+
#####
|
|
78
|
+
# Procedure input data for the set of expected patterns
|
|
79
|
+
#
|
|
80
|
+
def run
|
|
81
|
+
retval = @exp.expect(*@patterns.collect {|p| p.pattern})
|
|
82
|
+
unless (retval.nil?)
|
|
83
|
+
@exp.instance_eval(&@patterns[retval].block) unless (@patterns[retval].block.nil?)
|
|
84
|
+
end
|
|
85
|
+
return retval
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#####
|
|
90
|
+
# Expect each of a set of patterns
|
|
91
|
+
#
|
|
92
|
+
class EachMatch < Match
|
|
93
|
+
#####
|
|
94
|
+
# Procedure input data for the set of expected patterns
|
|
95
|
+
#
|
|
96
|
+
def run
|
|
97
|
+
@patterns.each_index do |i|
|
|
98
|
+
retval = @exp.expect(@patterns[i].pattern, &@patterns[i].block)
|
|
99
|
+
return nil if (retval.nil?)
|
|
100
|
+
end
|
|
101
|
+
return nil
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#####
|
|
106
|
+
# A procedure is a set of patterns to match and blocks to be called upon
|
|
107
|
+
# matching patterns. This is useful for building blocks of expected sequences
|
|
108
|
+
# of input data. An example of this could be logging into a system using SSH
|
|
109
|
+
#
|
|
110
|
+
# == Example
|
|
111
|
+
#
|
|
112
|
+
# retval = 0
|
|
113
|
+
# while (retval != 2)
|
|
114
|
+
# retval = any do
|
|
115
|
+
# expect /Are you sure you want to continue connecting \(yes\/no\)\?/ do
|
|
116
|
+
# send 'yes'
|
|
117
|
+
# end
|
|
118
|
+
#
|
|
119
|
+
# expect /password:\s*$/ do
|
|
120
|
+
# send password
|
|
121
|
+
# end
|
|
122
|
+
#
|
|
123
|
+
# expect /\$\s*$/ do
|
|
124
|
+
# send 'uptime'
|
|
125
|
+
# end
|
|
126
|
+
# end
|
|
127
|
+
# end
|
|
128
|
+
#
|
|
129
|
+
# # Expect each of the following
|
|
130
|
+
# each do
|
|
131
|
+
# expect /load\s+average:\s+\d+\.\d+,\s+\d+\.\d+,\s+\d+\.\d+/ do # expect the output of uptime
|
|
132
|
+
# puts last_match.to_s
|
|
133
|
+
# end
|
|
134
|
+
#
|
|
135
|
+
# expect /\$\s+$/ do # shell prompt
|
|
136
|
+
# send 'exit'
|
|
137
|
+
# end
|
|
138
|
+
# end
|
|
139
|
+
#
|
|
140
|
+
class Procedure
|
|
141
|
+
#####
|
|
142
|
+
# Create a new procedure to be executed by the expect object
|
|
143
|
+
#
|
|
144
|
+
# +exp_object+::
|
|
145
|
+
# The expect object that will execute this procedure
|
|
146
|
+
#
|
|
147
|
+
# +block+::
|
|
148
|
+
# The block to be called that defined the procedure
|
|
149
|
+
#
|
|
150
|
+
def initialize exp_object, &block
|
|
151
|
+
raise "First argument must be a RubyExpect::Expect object" unless (exp_object.is_a?(RubyExpect::Expect))
|
|
152
|
+
@exp = exp_object
|
|
153
|
+
@steps = []
|
|
154
|
+
instance_eval(&block) unless block.nil?
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
#####
|
|
158
|
+
# Add an 'any' block to the Procedure. The block will be evaluated using a
|
|
159
|
+
# new AnyMatch instance
|
|
160
|
+
#
|
|
161
|
+
# +block+::
|
|
162
|
+
# The block the specifies the patterns to expect
|
|
163
|
+
#
|
|
164
|
+
def any &block
|
|
165
|
+
RubyExpect::AnyMatch.new(@exp, &block).run
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
#####
|
|
169
|
+
# Add an 'each' block to the Procedure. The block will be evaluated using a
|
|
170
|
+
# new EachMatch instance
|
|
171
|
+
#
|
|
172
|
+
# +block+::
|
|
173
|
+
# The block that specifies the patterns to expect
|
|
174
|
+
#
|
|
175
|
+
def each &block
|
|
176
|
+
RubyExpect::EachMatch.new(@exp, &block).run
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ruby_expect
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 15
|
|
5
|
+
prerelease:
|
|
6
|
+
segments:
|
|
7
|
+
- 1
|
|
8
|
+
- 0
|
|
9
|
+
version: "1.0"
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- Andrew Bates
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2013-05-21 00:00:00 Z
|
|
18
|
+
dependencies: []
|
|
19
|
+
|
|
20
|
+
description: Ruby implementation for send/expect interaction
|
|
21
|
+
email: abates@omeganetserv.com
|
|
22
|
+
executables: []
|
|
23
|
+
|
|
24
|
+
extensions: []
|
|
25
|
+
|
|
26
|
+
extra_rdoc_files: []
|
|
27
|
+
|
|
28
|
+
files:
|
|
29
|
+
- lib/ruby_expect.rb
|
|
30
|
+
- lib/ruby_expect/expect.rb
|
|
31
|
+
- lib/ruby_expect/procedure.rb
|
|
32
|
+
homepage: https://github.com/abates/ruby_expect
|
|
33
|
+
licenses: []
|
|
34
|
+
|
|
35
|
+
post_install_message:
|
|
36
|
+
rdoc_options: []
|
|
37
|
+
|
|
38
|
+
require_paths:
|
|
39
|
+
- lib
|
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
hash: 3
|
|
46
|
+
segments:
|
|
47
|
+
- 0
|
|
48
|
+
version: "0"
|
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
|
+
none: false
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
hash: 3
|
|
55
|
+
segments:
|
|
56
|
+
- 0
|
|
57
|
+
version: "0"
|
|
58
|
+
requirements: []
|
|
59
|
+
|
|
60
|
+
rubyforge_project:
|
|
61
|
+
rubygems_version: 1.8.24
|
|
62
|
+
signing_key:
|
|
63
|
+
specification_version: 3
|
|
64
|
+
summary: This is a simple expect implementation that provides interactive access to IO objects
|
|
65
|
+
test_files: []
|
|
66
|
+
|