parley 0.2.0 → 0.2.1
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/README.md +130 -102
- data/VERSION +1 -1
- data/examples/parley_timed-read +7 -0
- data/lib/parley.rb +103 -14
- data/parley.gemspec +3 -2
- data/test/helper.rb +3 -2
- data/test/test_parley.rb +112 -10
- metadata +4 -3
data/README.md
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
======
|
1
|
+
# Parley
|
3
2
|
|
4
|
-
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
An expect-like module for Ruby modled after Perl's Expect.pm
|
5
6
|
|
6
7
|
Parley is an implementation of an expect-like API. It is designed to
|
7
|
-
help port away from Perl Expect based applications.
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
help port away from Perl Expect based applications.
|
9
|
+
|
10
|
+
The name "expect"
|
11
|
+
is already well established in ruby and varients of that name are in use by several gems.
|
12
|
+
"parley" was chosen as alternative to yet another expect-varient.
|
11
13
|
|
12
14
|
From http://www.thefreedictionary.com/parley "A discussion or conference, especially one between enemies over terms of truce or other matters."
|
13
15
|
|
@@ -15,116 +17,142 @@ See http://www.nist.gov/el/msid/expect.cfm for references to the original Expect
|
|
15
17
|
|
16
18
|
See http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod for information on Expect.pm
|
17
19
|
|
18
|
-
|
19
|
-
An expect-like module for Ruby modled after Perl's Expect.pm
|
20
|
+
## Duck Type Compatibility
|
20
21
|
|
21
|
-
Parley is a module that can be used with any class, like PTY
|
22
|
-
StringIO that
|
23
|
-
or
|
22
|
+
Parley is a module that can be used with any class, like `PTY`, `IO` or
|
23
|
+
`StringIO` that responds to `eof()`, and either `read_nonblock(maxread)`
|
24
|
+
or `getc()`.
|
24
25
|
|
25
|
-
If the
|
26
|
+
If the instance is valid for use with `Kernel.select()`, then Parley will be able to wait
|
26
27
|
for additional input to arrive.
|
27
28
|
|
28
|
-
|
29
|
+
## Parley method arguments
|
30
|
+
|
31
|
+
The `parley()` method is called with two arguments:
|
32
|
+
|
33
|
+
* an optional timeout in seconds, which may be 0 to indicate immediate timeout or `nil` to indicate no timeout
|
34
|
+
* additional arguments are arrays, each array containing a pattern and an action.
|
35
|
+
|
36
|
+
A call to parley with no arguments should read data until `eof?` and return `:eof`.
|
29
37
|
|
30
|
-
The parley() method is called with two arguments:
|
31
38
|
|
32
|
-
|
33
|
-
* an array of arrays, each array contains a pattern and an action.
|
39
|
+
### Each pattern is either:
|
34
40
|
|
35
|
-
|
41
|
+
* a `RegExp` to match input data
|
42
|
+
* the symbol `:timeout` to match the timeout condition from select()
|
43
|
+
* the symbol `:eof` to match the eof?() condition
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
|
45
|
+
If an action `responds_to?(:call)`, such as a `lambda{|m| code}`
|
46
|
+
then the action is called with `MatchData` as an argument.
|
47
|
+
In the case of `:timeout` or `:eof`, `MatchData` is from `matching:`
|
40
48
|
|
41
|
-
|
42
|
-
then the action is called with MatchData as an argument.
|
43
|
-
In the case of :timeout or :eof, MatchData is from matching:
|
44
|
-
input_buffer =~ /.*/
|
49
|
+
input_buffer =~ /.*/
|
45
50
|
|
46
|
-
|
51
|
+
## Examples of Usage
|
52
|
+
|
53
|
+
### Standard ruby expect vs. equivalent parley usage
|
54
|
+
|
55
|
+
In their simplest forms, the two are very similar:
|
56
|
+
|
57
|
+
* Expect takes a Regexp and an optional timeout
|
58
|
+
parameter. The method is either given a block that receives MatchData or it returns `MatchData`.
|
59
|
+
|
60
|
+
* Parley takes an optional `Numeric` timeout as the first argument and a variable
|
61
|
+
number of arrays, each containing a pattern and an action.
|
47
62
|
|
48
|
-
=== Standard ruby expect vs. equivalent parley usage
|
49
63
|
Standard Ruby expect:
|
50
|
-
require 'expect'
|
51
64
|
|
52
|
-
|
53
|
-
|
65
|
+
require 'expect'
|
66
|
+
...
|
67
|
+
input.expect(/pattern/, 10) {|matchdata| code} # wait up to 10 seconds
|
68
|
+
input.expect(/pattern/, 0) {|matchdata| code} # no waiting
|
69
|
+
input.expect(/pattern/) {|matchdata| code} # wait for a very long time
|
54
70
|
|
55
71
|
Parley:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
72
|
+
|
73
|
+
require 'parley'
|
74
|
+
|
75
|
+
...
|
76
|
+
input.extend Parley # needed if input is not a subclass of IO
|
77
|
+
...
|
78
|
+
input.parley(10, [/pattern/, lambda{|matchdata| code}]) # wait up to 10 seconds
|
79
|
+
input.parley(0, [/pattern/, lambda{|matchdata| code}]) # no waiting
|
80
|
+
input.parley(nil, [/pattern/, lambda{|matchdata| code}]) # wait forever
|
81
|
+
input.parley([/pattern/, lambda{|matchdata| code}]) # wait forever
|
82
|
+
|
83
|
+
## Telnet login using /usr/bin/telnet
|
84
|
+
See the examples directory for a use of Net::Telnet instead of PTY.spawn(...
|
85
|
+
|
86
|
+
require 'parley'
|
87
|
+
input, output, process_id = PTY.spawn("/usr/bin/telnet localhost")
|
88
|
+
output.puts '' # hit return to make sure we get some output
|
89
|
+
result = input.parley(30, [ # allow 30 seconds to login
|
90
|
+
[ /ogin:/, lambda{|m| output.puts 'username'; :continue} ],
|
91
|
+
[ /ssword:/, lambda{|m| output.puts 'my-secret-password'; :continue} ],
|
92
|
+
[ /refused/i, "connection refused" ],
|
93
|
+
[ :timeout, "timed out" ],
|
94
|
+
[ :eof, "command output closed" ],
|
95
|
+
[ /\$/, true ] # some string that only appears in the shell prompt
|
96
|
+
])
|
97
|
+
if result == true
|
98
|
+
puts "Successful login"
|
99
|
+
output.puts "date" # This is the important command we had to run
|
100
|
+
else
|
101
|
+
puts "Login failed because: #{result}"
|
102
|
+
end
|
103
|
+
# We can keep running commands.
|
104
|
+
input.close
|
105
|
+
output.close
|
106
|
+
id, exit_status = Process.wait2(process_id)
|
107
|
+
|
108
|
+
### Run your telnet script against canned input
|
109
|
+
|
110
|
+
require 'parley'
|
111
|
+
class StringIO
|
112
|
+
include Parley # or use "input.extend Parley"
|
113
|
+
end
|
114
|
+
input = StringIO.new("login: password: prompt$\n", "r")
|
115
|
+
output = StringIO.new("", "w")
|
116
|
+
output.puts '' # Note: no effect in this example
|
117
|
+
result = input.parley(30, [ # Note: timeout has no effect for StringIO
|
118
|
+
# XXX check these example patterns against need for anchoring with ^ and/or $
|
119
|
+
[ /ogin:/, lambda{|m| output.puts 'username'; :continue} ],
|
120
|
+
[ /ssword:/, lambda{|m| output.puts 'my-secret-password'; :continue} ],
|
121
|
+
[ :timeout, "timed out" ],
|
122
|
+
[ :eof, "command output closed" ],
|
123
|
+
[ /\$/, true ] # some string that only appears in the shell prompt
|
124
|
+
])
|
125
|
+
if result == true
|
126
|
+
puts "Successful login"
|
127
|
+
output.puts "exit"
|
128
|
+
else
|
129
|
+
puts "Login failed because: #{result}"
|
130
|
+
end
|
131
|
+
input.close
|
132
|
+
output.close
|
133
|
+
id, exit_status = Process.wait2(process_id)
|
134
|
+
|
135
|
+
### Handle a timeout condition
|
136
|
+
|
137
|
+
require 'parley'
|
138
|
+
read, write, pid = PTY.spawn("ruby -e 'sleep 20'")
|
139
|
+
result = read.parley(5, ["timeout, :timeout])
|
140
|
+
if result == :timeout
|
141
|
+
puts "Program timed-out as expected"
|
142
|
+
else
|
143
|
+
puts "Error, timeout did not happen!"
|
144
|
+
end
|
145
|
+
|
146
|
+
## Known Issues
|
147
|
+
|
148
|
+
* *FIXED!* `:reset_timeout` from IO::parley() doesn't have the desired effect, it isn't re-establishing the timeout.
|
149
|
+
* *FIXED!* need to generatate adequte documentation. See `test/test_parley.rb` for now
|
124
150
|
* line oriented reading option
|
125
|
-
* Finer grain greediness control beyond read_nonblock(maxlen)
|
151
|
+
* Finer grain greediness control beyond `read_nonblock(maxlen)`
|
152
|
+
|
153
|
+
## Contributing to parley
|
154
|
+
--
|
126
155
|
|
127
|
-
== Contributing to parley
|
128
156
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
129
157
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
130
158
|
* Fork the project.
|
@@ -133,7 +161,7 @@ Parley:
|
|
133
161
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
134
162
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
135
163
|
|
136
|
-
|
164
|
+
## Copyright
|
137
165
|
|
138
|
-
Copyright
|
166
|
+
Copyright © 2013 Ben Stoltz.
|
139
167
|
See LICENSE.txt for further details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# Ported from Don Libes' example for tcl expect: expect_timed-read
|
3
|
+
# read a complete line from stdin
|
4
|
+
# aborting after the number of seconds (given as an argument)
|
5
|
+
require 'parley'
|
6
|
+
|
7
|
+
STDIN.parley ARGV[0].to_i, [/^(.*)\n/, lambda{|m| puts m}], [:timeout, nil]
|
data/lib/parley.rb
CHANGED
@@ -1,6 +1,75 @@
|
|
1
1
|
|
2
2
|
require 'pty'
|
3
3
|
|
4
|
+
# The Parley module is generally used to wrestle with the informal, interactive, text-mode,
|
5
|
+
# APIs of the world.
|
6
|
+
#
|
7
|
+
# Parley is an implementation of an expect-like API. It is designed to
|
8
|
+
# help port away from Perl Expect based applications.
|
9
|
+
# Parley was chosen as a name as an alternative to the various "expect" like
|
10
|
+
# names already in use by other implementations.
|
11
|
+
#
|
12
|
+
# The {definition of "parley"}[http://www.thefreedictionary.com/parley] used
|
13
|
+
# here is: "A discussion or conference, especially one between enemies over
|
14
|
+
# terms of truce or other matters."
|
15
|
+
#
|
16
|
+
# See {the original Expect site at NIST}[http://www.nist.gov/el/msid/expect.cfm] for
|
17
|
+
# references to the original Expect language based on Tcl.
|
18
|
+
#
|
19
|
+
# See the {Perl Expect.pm module}[http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod].
|
20
|
+
#
|
21
|
+
# === Compatibility
|
22
|
+
# Parley can be used with any class, like PTY, IO or
|
23
|
+
# StringIO that responds_to?() :eof?, and either :read_nonblock(maxread) or :getc.
|
24
|
+
#
|
25
|
+
# If the class also responds to :select, ala IO##select, then Parley will be able to wait
|
26
|
+
# for additional input to arrive.
|
27
|
+
#
|
28
|
+
# === Monkey Patching
|
29
|
+
# require 'parley' will automatcially add parley() and support methods to the IO class
|
30
|
+
#
|
31
|
+
# Author:: Ben Stoltz (mailto:gem-parley@lzrd.com)
|
32
|
+
# Copyright:: Copyright (c) 2013 Benjamin Stoltz
|
33
|
+
# License:: See LICENSE.txt distributed with this file
|
34
|
+
#
|
35
|
+
# == Examples
|
36
|
+
# === Standard ruby expect vs. equivalent parley usage
|
37
|
+
# Standard Ruby expect:
|
38
|
+
# require 'expect'
|
39
|
+
#
|
40
|
+
# ...
|
41
|
+
# input.expect(/pattern/, 10) {|matchdata| code}
|
42
|
+
#
|
43
|
+
# Parley:
|
44
|
+
# require 'parley'
|
45
|
+
#
|
46
|
+
# ...
|
47
|
+
# input.parley(10, [/pattern/, lambda{|matchdata| code}])
|
48
|
+
#
|
49
|
+
# === Telnet login using /usr/bin/telnet
|
50
|
+
# require 'parley'
|
51
|
+
# input, output, process_id = PTY.spawn("/usr/bin/telnet localhost")
|
52
|
+
# output.puts '' # hit return to make sure we get some output
|
53
|
+
# result = input.parley(30, # allow 30 seconds to login
|
54
|
+
# [ /ogin:/, lambda{|m| output.puts 'username'; :continue} ],
|
55
|
+
# [ /ssword:/, lambda{|m| output.puts 'my-secret-password'; :continue} ],
|
56
|
+
# [ /refused/i, "connection refused" ],
|
57
|
+
# [ :timeout, "timed out" ],
|
58
|
+
# [ :eof, "command output closed" ],
|
59
|
+
# [ /\$/, true ] # some string that only appears in the shell prompt
|
60
|
+
# ])
|
61
|
+
# if result == true
|
62
|
+
# puts "Successful login"
|
63
|
+
# output.puts "date" # This is the important command we had to run
|
64
|
+
# else
|
65
|
+
# puts "Login failed because: #{result}"
|
66
|
+
# end
|
67
|
+
# # We can keep running commands.
|
68
|
+
# input.close
|
69
|
+
# output.close
|
70
|
+
# id, exit_status = Process.wait2(process_id)
|
71
|
+
#
|
72
|
+
|
4
73
|
module Parley
|
5
74
|
# Internal: used to set input data that has been received, but not yet matched
|
6
75
|
#--
|
@@ -11,7 +80,8 @@ module Parley
|
|
11
80
|
@unused_buf = v
|
12
81
|
end
|
13
82
|
|
14
|
-
# holds the remaining input read from +read_nonblock()+ or +getc()+ but not
|
83
|
+
# holds the remaining input read from +read_nonblock()+ or +getc()+ but not
|
84
|
+
# yet used
|
15
85
|
def unused_buf
|
16
86
|
@unused_buf = nil unless defined? @unused_buf
|
17
87
|
@unused_buf
|
@@ -42,37 +112,56 @@ module Parley
|
|
42
112
|
@parley_maxread
|
43
113
|
end
|
44
114
|
|
45
|
-
#
|
46
|
-
#
|
115
|
+
# Collect data, from an IO-like object while matching
|
116
|
+
# match patterns and conditions (i.e. EOF and Timeout) and take corresponding
|
117
|
+
# actions until an action returns a value not equal to +:continue+ or
|
118
|
+
# +:reset_timeout+
|
119
|
+
#
|
120
|
+
# The parley() method is called with two arguments:
|
121
|
+
#
|
122
|
+
# +timeout_seconds+ specifies the amount of time before the +:timeout+
|
123
|
+
# condition is presented to the pattern/action list.
|
124
|
+
#
|
125
|
+
# a variable number of arrays, each array contains a pattern and an action.
|
47
126
|
#
|
48
|
-
# +timeout_seconds+
|
49
|
-
#
|
127
|
+
# * +timeout_seconds+ = nil disables timeout.
|
128
|
+
# * +timeout_seconds+ <= 0 times out immediately as soon as no data is present
|
129
|
+
# * +timeout_seconds+ > 0 times out seconds after parley was called unless
|
130
|
+
# timer is reset by an action returning :reset_timeout
|
50
131
|
#
|
51
|
-
#
|
52
|
-
#
|
132
|
+
# A pattern is either:
|
133
|
+
# * a RegExp to match input data
|
134
|
+
# * the symbol :timeout to match the timeout condition from select()
|
135
|
+
# * the symbol :eof to match the eof?() condition
|
53
136
|
#
|
54
|
-
#
|
137
|
+
# If an action responds_to?(:call), such as a lambda{|m| code}
|
138
|
+
# then the action is called with MatchData as an argument.
|
139
|
+
# In the case of :timeout or :eof, MatchData is from matching:
|
55
140
|
#
|
56
|
-
#
|
141
|
+
# input_buffer =~ /.*/
|
57
142
|
#
|
58
143
|
# A action returning the value +:reset_timeout+ will +:continue+ and reset
|
59
144
|
# the timeout deadline to a value of +Time.now+ + +timeout_seconds+
|
145
|
+
#
|
60
146
|
def parley (timeout_seconds, *actions)
|
61
|
-
@pvout.
|
62
|
-
|
147
|
+
@pvout.puts "parley: timeout_seconds=#{timeout_seconds}" if parley_verbose
|
148
|
+
case timeout_seconds
|
149
|
+
when NilClass
|
63
150
|
deadline = nil
|
64
|
-
|
151
|
+
when Numeric
|
65
152
|
deadline = Time.now + timeout_seconds
|
153
|
+
else
|
154
|
+
raise "Invalid timeout parameter: #{timeout_seconds.inspect}"
|
66
155
|
end
|
67
156
|
buf = ''
|
68
|
-
unused_buf
|
157
|
+
unused_buf ||= ''
|
69
158
|
|
70
159
|
# XXX Compatible hack. There are changes coming w.r.t. respond_to? for
|
71
160
|
# protected methods. Just do a simple poll, and see if it works.
|
72
161
|
begin
|
73
162
|
result = IO.select([self], [], [], 0)
|
74
163
|
has_select = true;
|
75
|
-
rescue Exception
|
164
|
+
rescue Exception # NoMethodError and ArgumentError are common
|
76
165
|
has_select = false;
|
77
166
|
end
|
78
167
|
|
data/parley.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "parley"
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ben Stoltz"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-03-14"
|
13
13
|
s.description = "An expect-like gem, modeled after Perl's Expect.pm"
|
14
14
|
s.email = "stoltz@lzrd.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
"README.md",
|
24
24
|
"Rakefile",
|
25
25
|
"VERSION",
|
26
|
+
"examples/parley_timed-read",
|
26
27
|
"lib/parley.rb",
|
27
28
|
"parley.gemspec",
|
28
29
|
"test/helper.rb",
|
data/test/helper.rb
CHANGED
@@ -10,8 +10,9 @@ end
|
|
10
10
|
require 'test/unit'
|
11
11
|
# require 'shoulda'
|
12
12
|
|
13
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '
|
14
|
-
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
14
|
+
#$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
|
15
16
|
require 'parley'
|
16
17
|
|
17
18
|
class Test::Unit::TestCase
|
data/test/test_parley.rb
CHANGED
@@ -29,12 +29,113 @@ class TestIO < Test::Unit::TestCase
|
|
29
29
|
# no teardown required
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def test_timeout_positive
|
33
33
|
read, write, pid = PTY.spawn('/bin/sleep 20')
|
34
34
|
result = read.parley(5, [:timeout, :timeout])
|
35
35
|
assert(result == :timeout, "** ERROR result = #{result}")
|
36
36
|
end
|
37
37
|
|
38
|
+
# Negative timeout behaves like zero since that time is already passed.
|
39
|
+
def test_negative_timeout
|
40
|
+
sleep_seconds = 5
|
41
|
+
read, write, pid = PTY.spawn("/bin/sleep #{sleep_seconds}")
|
42
|
+
start_time = Time.now
|
43
|
+
result = read.parley(-1, [:timeout, :timeout])
|
44
|
+
delta_t = Time.now - start_time
|
45
|
+
assert(result == :timeout, "** ERROR result = #{result}")
|
46
|
+
assert(delta_t < sleep_seconds/2,
|
47
|
+
"Immediate timeout did not happen: delta_t = #{delta_t}")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Zero timeout results in immediate :timeout if no data available
|
51
|
+
def test_zero_timeout
|
52
|
+
sleep_seconds = 10
|
53
|
+
read, write, pid = PTY.spawn("/bin/sleep #{sleep_seconds}")
|
54
|
+
start_time = Time.now
|
55
|
+
result = read.parley(0, [:timeout, :timeout], [:eof, :eof])
|
56
|
+
end_time = Time.now
|
57
|
+
delta_t = (end_time - start_time)
|
58
|
+
assert(result == :timeout, "** ERROR result = #{result}")
|
59
|
+
assert(delta_t < (sleep_seconds/2.0),
|
60
|
+
"Test ended too late: delta_t(#{delta_t}) >= #{sleep_seconds/2.0}")
|
61
|
+
end
|
62
|
+
|
63
|
+
=begin
|
64
|
+
# This syntax is not final or implemented yet
|
65
|
+
def test_multiple_spawned_commands
|
66
|
+
total = 0
|
67
|
+
count = 0
|
68
|
+
|
69
|
+
commands1 = []
|
70
|
+
(1..5).each do |i|
|
71
|
+
# push [read, write, pid] onto commands
|
72
|
+
commands1 << PTY.spawn("sleep 3; echo N=#{i}; sleep 2")
|
73
|
+
end
|
74
|
+
pattern_action_1 = [
|
75
|
+
/N=(\d+)/, # find this pattern in output of all commands
|
76
|
+
lambda do |m, r, w|
|
77
|
+
total += m[1].to_i
|
78
|
+
count += 1
|
79
|
+
:continue; # we don't want to terminate the expect call
|
80
|
+
end
|
81
|
+
]
|
82
|
+
|
83
|
+
commands2 = []
|
84
|
+
(6..10).each do |i|
|
85
|
+
# push [read, write, pid] onto commands
|
86
|
+
commands2 << PTY.spawn("sleep 3; echo X=#{i}; sleep 2")
|
87
|
+
end
|
88
|
+
pattern_action_2 = [
|
89
|
+
/X=(\d+)/, # find this pattern in output of all commands
|
90
|
+
lambda do |m, r, w|
|
91
|
+
total += m[1].to_i
|
92
|
+
count += 1
|
93
|
+
:continue; # we don't want to terminate the expect call
|
94
|
+
end
|
95
|
+
]
|
96
|
+
|
97
|
+
result = total / (count * 1.0)
|
98
|
+
|
99
|
+
sum = 0
|
100
|
+
(1..10).each do |i|
|
101
|
+
sum += i
|
102
|
+
end
|
103
|
+
avg = sum/10.0
|
104
|
+
|
105
|
+
parley_multiple(15,
|
106
|
+
[commands1, pattern_action_1],
|
107
|
+
[commands2, pattern_action_2])
|
108
|
+
|
109
|
+
assert(avg == result, "Error avg(#{avg}) != result(#{result}))")
|
110
|
+
end
|
111
|
+
=end
|
112
|
+
|
113
|
+
def test_nil_timeout
|
114
|
+
sleep_seconds = 10
|
115
|
+
read, write, pid = PTY.spawn("/bin/sleep #{sleep_seconds}")
|
116
|
+
start_time = Time.now
|
117
|
+
result = read.parley(nil, [:timeout, :timeout], [:eof, :eof])
|
118
|
+
delta_t = Time.now - start_time
|
119
|
+
assert(result == :eof, "** ERROR result = #{result}")
|
120
|
+
assert(delta_t >= sleep_seconds - 1,
|
121
|
+
"Test ended too quickly: delta_t = #{delta_t}")
|
122
|
+
end
|
123
|
+
|
124
|
+
=begin
|
125
|
+
# Alternate API, no timeout: parley([pattern, action], ...)
|
126
|
+
# timeout_seconds defaults to nil which means "no timeout"
|
127
|
+
def test_missing_timeout
|
128
|
+
sleep_seconds = 10
|
129
|
+
read, write, pid = PTY.spawn("/bin/sleep #{sleep_seconds}")
|
130
|
+
start_time = Time.now
|
131
|
+
result = read.parley([:timeout, :timeout], [:eof, :eof])
|
132
|
+
delta_t = Time.now - start_time
|
133
|
+
assert(result == :eof, "** ERROR result = #{result}")
|
134
|
+
assert(delta_t >= sleep_seconds - 1,
|
135
|
+
"Test ended too quickly: delta_t = #{delta_t}")
|
136
|
+
end
|
137
|
+
=end
|
138
|
+
|
38
139
|
def test_single_match
|
39
140
|
sin = StringIO.new(@text)
|
40
141
|
result = sin.parley(0,
|
@@ -45,6 +146,7 @@ class TestIO < Test::Unit::TestCase
|
|
45
146
|
assert(result == "just apple", "Invalid result(#{result})")
|
46
147
|
end
|
47
148
|
|
149
|
+
|
48
150
|
def test_eof_constant
|
49
151
|
io = File.new("/dev/null", "r")
|
50
152
|
result = io.parley(20, [:eof, :eof])
|
@@ -307,15 +409,15 @@ class TestIO < Test::Unit::TestCase
|
|
307
409
|
[
|
308
410
|
:timeout,
|
309
411
|
lambda do |m|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
412
|
+
sin.puts ""
|
413
|
+
@n_to_reset += 1
|
414
|
+
puts "Resetting timeout #{@n_to_reset}"
|
415
|
+
if @n_to_reset > 2
|
416
|
+
sin.puts "exit"
|
417
|
+
"Timeout"
|
418
|
+
else
|
419
|
+
:reset_timeout
|
420
|
+
end
|
319
421
|
end
|
320
422
|
])
|
321
423
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rdoc
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- README.md
|
74
74
|
- Rakefile
|
75
75
|
- VERSION
|
76
|
+
- examples/parley_timed-read
|
76
77
|
- lib/parley.rb
|
77
78
|
- parley.gemspec
|
78
79
|
- test/helper.rb
|
@@ -92,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
93
|
version: '0'
|
93
94
|
segments:
|
94
95
|
- 0
|
95
|
-
hash: -
|
96
|
+
hash: -3261750928245830476
|
96
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
98
|
none: false
|
98
99
|
requirements:
|