parley 0.1.0 → 0.2.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/README.md +109 -9
 - data/VERSION +1 -1
 - data/lib/parley.rb +74 -58
 - data/parley.gemspec +4 -6
 - data/test/test_parley.rb +150 -36
 - metadata +4 -6
 - data/README.rdoc +0 -35
 
    
        data/README.md
    CHANGED
    
    | 
         @@ -15,15 +15,116 @@ See http://www.nist.gov/el/msid/expect.cfm for references to the original Expect 
     | 
|
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
            See http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod for information on Expect.pm
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 18 
     | 
    
         
            +
            = Parley 
         
     | 
| 
      
 19 
     | 
    
         
            +
            An expect-like module for Ruby modled after Perl's Expect.pm
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
      
 21 
     | 
    
         
            +
            Parley is a module that can be used with any class, like PTY, IO or
         
     | 
| 
      
 22 
     | 
    
         
            +
            StringIO that responds_to?() :eof?, and either :read_nonblock(maxread)
         
     | 
| 
      
 23 
     | 
    
         
            +
            or :getc.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            If the class also responds to :select, then Parley will be able to wait
         
     | 
| 
      
 26 
     | 
    
         
            +
            for additional input to arrive.
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            == parley method arguments
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            The parley() method is called with two arguments:
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            * a timeout in seconds, which may be zero to indicate no timeout
         
     | 
| 
      
 33 
     | 
    
         
            +
            * an array of arrays, each array contains a pattern and an action.
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            Each pattern is either:
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            * a RegExp to match input data
         
     | 
| 
      
 38 
     | 
    
         
            +
            * the symbol :timeout to match the timeout condition from select()
         
     | 
| 
      
 39 
     | 
    
         
            +
            * the symbol :eof to match the eof?() condition
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            If an action responds_to?(:call), such as a lambda{|m| code}
         
     | 
| 
      
 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 =~ /.*/
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            == Examples of Usage
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            === Standard ruby expect vs. equivalent parley usage
         
     | 
| 
      
 49 
     | 
    
         
            +
            Standard Ruby expect:
         
     | 
| 
      
 50 
     | 
    
         
            +
              require 'expect'
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              ...
         
     | 
| 
      
 53 
     | 
    
         
            +
              input.expect(/pattern/, 10) {|matchdata| code}
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            Parley:
         
     | 
| 
      
 56 
     | 
    
         
            +
              require 'parley'
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              ...
         
     | 
| 
      
 59 
     | 
    
         
            +
              input.parley(10, [[/pattern/, lambda{|matchdata| code}]])
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            === Telnet login using /usr/bin/telnet
         
     | 
| 
      
 62 
     | 
    
         
            +
             require 'parley'
         
     | 
| 
      
 63 
     | 
    
         
            +
             input, output, process_id = PTY.spawn("/usr/bin/telnet localhost")
         
     | 
| 
      
 64 
     | 
    
         
            +
             output.puts '' # hit return to make sure we get some output
         
     | 
| 
      
 65 
     | 
    
         
            +
             result = input.parley(30, [  # allow 30 seconds to login
         
     | 
| 
      
 66 
     | 
    
         
            +
               [ /ogin:/, lambda{|m| output.puts 'username'; :continue} ],
         
     | 
| 
      
 67 
     | 
    
         
            +
               [ /ssword:/, lambda{|m| output.puts 'my-secret-password'; :continue} ],
         
     | 
| 
      
 68 
     | 
    
         
            +
               [ /refused/i, "connection refused" ],
         
     | 
| 
      
 69 
     | 
    
         
            +
               [ :timeout, "timed out" ],
         
     | 
| 
      
 70 
     | 
    
         
            +
               [ :eof, "command output closed" ],
         
     | 
| 
      
 71 
     | 
    
         
            +
               [ /\$/, true ] # some string that only appears in the shell prompt
         
     | 
| 
      
 72 
     | 
    
         
            +
               ])
         
     | 
| 
      
 73 
     | 
    
         
            +
             if result == true
         
     | 
| 
      
 74 
     | 
    
         
            +
               puts "Successful login"
         
     | 
| 
      
 75 
     | 
    
         
            +
               output.puts "date" # This is the important command we had to run
         
     | 
| 
      
 76 
     | 
    
         
            +
             else
         
     | 
| 
      
 77 
     | 
    
         
            +
               puts "Login failed because: #{result}"
         
     | 
| 
      
 78 
     | 
    
         
            +
             end
         
     | 
| 
      
 79 
     | 
    
         
            +
             # We can keep running commands.
         
     | 
| 
      
 80 
     | 
    
         
            +
             input.close
         
     | 
| 
      
 81 
     | 
    
         
            +
             output.close
         
     | 
| 
      
 82 
     | 
    
         
            +
             id, exit_status = Process.wait2(process_id)
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            === Run your telnet script against canned input
         
     | 
| 
      
 85 
     | 
    
         
            +
             require 'parley'
         
     | 
| 
      
 86 
     | 
    
         
            +
             class StringIO
         
     | 
| 
      
 87 
     | 
    
         
            +
               include Parley
         
     | 
| 
      
 88 
     | 
    
         
            +
             end
         
     | 
| 
      
 89 
     | 
    
         
            +
             input = StringIO.new("login: password: prompt$\n", "r")
         
     | 
| 
      
 90 
     | 
    
         
            +
             output = StringIO.new("", "w")
         
     | 
| 
      
 91 
     | 
    
         
            +
             output.puts '' # Note: no effect in this example
         
     | 
| 
      
 92 
     | 
    
         
            +
             result = input.parley(30, [  # Note: timeout has no effect for StringIO
         
     | 
| 
      
 93 
     | 
    
         
            +
               # XXX check these example patterns against need for anchoring with ^ and/or $
         
     | 
| 
      
 94 
     | 
    
         
            +
               [ /ogin:/, lambda{|m| output.puts 'username'; :continue} ],
         
     | 
| 
      
 95 
     | 
    
         
            +
               [ /ssword:/, lambda{|m| output.puts 'my-secret-password'; :continue} ],
         
     | 
| 
      
 96 
     | 
    
         
            +
               [ :timeout, "timed out" ],
         
     | 
| 
      
 97 
     | 
    
         
            +
               [ :eof, "command output closed" ],
         
     | 
| 
      
 98 
     | 
    
         
            +
               [ /\$/, true ] # some string that only appears in the shell prompt
         
     | 
| 
      
 99 
     | 
    
         
            +
               ])
         
     | 
| 
      
 100 
     | 
    
         
            +
             if result == true
         
     | 
| 
      
 101 
     | 
    
         
            +
               puts "Successful login"
         
     | 
| 
      
 102 
     | 
    
         
            +
               output.puts "exit"
         
     | 
| 
      
 103 
     | 
    
         
            +
             else
         
     | 
| 
      
 104 
     | 
    
         
            +
               puts "Login failed because: #{result}"
         
     | 
| 
      
 105 
     | 
    
         
            +
             end
         
     | 
| 
      
 106 
     | 
    
         
            +
             input.close
         
     | 
| 
      
 107 
     | 
    
         
            +
             output.close
         
     | 
| 
      
 108 
     | 
    
         
            +
             id, exit_status = Process.wait2(process_id)
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            === Handle a timeout condition
         
     | 
| 
      
 111 
     | 
    
         
            +
             require 'parley'
         
     | 
| 
      
 112 
     | 
    
         
            +
             read, write, pid = PTY.spawn("ruby -e 'sleep 20'")
         
     | 
| 
      
 113 
     | 
    
         
            +
             result = read.parley(5, ["timeout, :timeout])
         
     | 
| 
      
 114 
     | 
    
         
            +
             if result == :timeout
         
     | 
| 
      
 115 
     | 
    
         
            +
              puts "Program timed-out as expected"
         
     | 
| 
      
 116 
     | 
    
         
            +
             else
         
     | 
| 
      
 117 
     | 
    
         
            +
              puts "Error, timeout did not happen!"
         
     | 
| 
      
 118 
     | 
    
         
            +
             end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
            == Known Issues
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
            * :reset_timeout from IO::parley() doesn't have the desired effect, it isn't re-establishing the timeout.
         
     | 
| 
       21 
123 
     | 
    
         
             
            * need to generatate adequte documentation. See test/test_parley.rb for now
         
     | 
| 
       22 
     | 
    
         
            -
            *  
     | 
| 
      
 124 
     | 
    
         
            +
            * line oriented reading option
         
     | 
| 
      
 125 
     | 
    
         
            +
            * Finer grain greediness control beyond read_nonblock(maxlen)
         
     | 
| 
       23 
126 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
            Contributing to parley
         
     | 
| 
       25 
     | 
    
         
            -
            ----------------------
         
     | 
| 
       26 
     | 
    
         
            -
             
         
     | 
| 
      
 127 
     | 
    
         
            +
            == Contributing to parley
         
     | 
| 
       27 
128 
     | 
    
         
             
            * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
         
     | 
| 
       28 
129 
     | 
    
         
             
            * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
         
     | 
| 
       29 
130 
     | 
    
         
             
            * Fork the project.
         
     | 
| 
         @@ -32,8 +133,7 @@ Contributing to parley 
     | 
|
| 
       32 
133 
     | 
    
         
             
            * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
         
     | 
| 
       33 
134 
     | 
    
         
             
            * 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.
         
     | 
| 
       34 
135 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
            Copyright
         
     | 
| 
       36 
     | 
    
         
            -
            ---------
         
     | 
| 
      
 136 
     | 
    
         
            +
            == Copyright
         
     | 
| 
       37 
137 
     | 
    
         | 
| 
       38 
138 
     | 
    
         
             
            Copyright (c) 2013 Ben Stoltz.
         
     | 
| 
       39 
     | 
    
         
            -
            See LICENSE.txt for further details.
         
     | 
| 
      
 139 
     | 
    
         
            +
            See LICENSE.txt for further details.
         
     | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            0. 
     | 
| 
      
 1 
     | 
    
         
            +
            0.2.0
         
     | 
    
        data/lib/parley.rb
    CHANGED
    
    | 
         @@ -1,130 +1,143 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
            #
         
     | 
| 
       3 
     | 
    
         
            -
            # = parley.rb - An expect library for Ruby modled after Perl's Expect.pm
         
     | 
| 
       4 
     | 
    
         
            -
            #
         
     | 
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
       5 
2 
     | 
    
         
             
            require 'pty'
         
     | 
| 
       6 
3 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            # TODO: line oriented reading option
         
     | 
| 
       8 
     | 
    
         
            -
            # Greediness control
         
     | 
| 
       9 
4 
     | 
    
         
             
            module Parley
         
     | 
| 
       10 
     | 
    
         
            -
              #  
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
              # Internal: used to set input data that has been received, but not yet matched
         
     | 
| 
      
 6 
     | 
    
         
            +
              #--
         
     | 
| 
       12 
7 
     | 
    
         
             
              # Initialize() is usually not called or doesn't call super(), so
         
     | 
| 
       13 
8 
     | 
    
         
             
              # do implicit instance variable initialization
         
     | 
| 
      
 9 
     | 
    
         
            +
              #++
         
     | 
| 
       14 
10 
     | 
    
         
             
              def unused_buf= (v)
         
     | 
| 
       15 
11 
     | 
    
         
             
                @unused_buf = v
         
     | 
| 
       16 
12 
     | 
    
         
             
              end
         
     | 
| 
       17 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
              # holds the remaining input read from +read_nonblock()+ or +getc()+ but not yet used
         
     | 
| 
       18 
15 
     | 
    
         
             
              def unused_buf
         
     | 
| 
       19 
16 
     | 
    
         
             
                @unused_buf = nil unless defined? @unused_buf
         
     | 
| 
       20 
17 
     | 
    
         
             
                @unused_buf
         
     | 
| 
       21 
18 
     | 
    
         
             
              end
         
     | 
| 
       22 
19 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
               
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 20 
     | 
    
         
            +
              # Sets/clears verbose mode to aid debugging.
         
     | 
| 
      
 21 
     | 
    
         
            +
              #
         
     | 
| 
      
 22 
     | 
    
         
            +
              # Debug output is sent to +STDOUT+ unless overridden by +pvout+
         
     | 
| 
      
 23 
     | 
    
         
            +
              def parley_verbose= (truth, pvout = STDOUT)
         
     | 
| 
      
 24 
     | 
    
         
            +
                @pvout = pvout
         
     | 
| 
      
 25 
     | 
    
         
            +
                @parley_verbose = (truth ? true : false)
         
     | 
| 
       25 
26 
     | 
    
         
             
              end
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
      
 28 
     | 
    
         
            +
              # returns +true+ if debug output is enabled, else +false+
         
     | 
| 
       27 
29 
     | 
    
         
             
              def parley_verbose
         
     | 
| 
       28 
30 
     | 
    
         
             
                @parley_verbose = false unless defined? @parley_verbose
         
     | 
| 
       29 
31 
     | 
    
         
             
                @parley_verbose
         
     | 
| 
       30 
32 
     | 
    
         
             
              end
         
     | 
| 
       31 
33 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
               
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
      
 34 
     | 
    
         
            +
              # sets the maximum number of characters to read from +read_nonblock()+
         
     | 
| 
      
 35 
     | 
    
         
            +
              def parley_maxread= (max_characters = 1)
         
     | 
| 
      
 36 
     | 
    
         
            +
                @parley_maxread = (max_characters > 0) ? max_characters : 1
         
     | 
| 
       34 
37 
     | 
    
         
             
              end
         
     | 
| 
       35 
38 
     | 
    
         | 
| 
      
 39 
     | 
    
         
            +
              # return the maximum number of characters to read from +read_nonblock()+
         
     | 
| 
       36 
40 
     | 
    
         
             
              def parley_maxread
         
     | 
| 
       37 
41 
     | 
    
         
             
                @parley_maxread = 1 unless defined? @parley_maxread
         
     | 
| 
       38 
42 
     | 
    
         
             
                @parley_maxread
         
     | 
| 
       39 
43 
     | 
    
         
             
              end
         
     | 
| 
       40 
44 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
               
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
      
 45 
     | 
    
         
            +
              # Match patterns and conditions and take corresponding actions until an action
         
     | 
| 
      
 46 
     | 
    
         
            +
              # returns a value not equal to +:continue+ or +:reset_timeout+
         
     | 
| 
      
 47 
     | 
    
         
            +
              #
         
     | 
| 
      
 48 
     | 
    
         
            +
              # +timeout_seconds+ specifies the amount of time before the +:timeout+ condition
         
     | 
| 
      
 49 
     | 
    
         
            +
              # is presented to the pattern/action list.
         
     | 
| 
      
 50 
     | 
    
         
            +
              #
         
     | 
| 
      
 51 
     | 
    
         
            +
              # If +timeout_seconds+ is less than or equal to zero, then +:timeout+
         
     | 
| 
      
 52 
     | 
    
         
            +
              # immediately as soon as there is no more data available.
         
     | 
| 
      
 53 
     | 
    
         
            +
              #
         
     | 
| 
      
 54 
     | 
    
         
            +
              # XXX bad. output could spew forever and we want to stop by deadline.
         
     | 
| 
      
 55 
     | 
    
         
            +
              #
         
     | 
| 
      
 56 
     | 
    
         
            +
              # If +timeout_seconds+ is nil, then no +:timeout+ condition will be generated.
         
     | 
| 
      
 57 
     | 
    
         
            +
              #
         
     | 
| 
      
 58 
     | 
    
         
            +
              # A action returning the value +:reset_timeout+ will +:continue+ and reset
         
     | 
| 
      
 59 
     | 
    
         
            +
              # the timeout deadline to a value of +Time.now+ + +timeout_seconds+
         
     | 
| 
      
 60 
     | 
    
         
            +
              def parley (timeout_seconds, *actions)
         
     | 
| 
      
 61 
     | 
    
         
            +
                @pvout.print "parley,#{__LINE__}: timeout_seconds=#{timeout_seconds}\n" if parley_verbose
         
     | 
| 
      
 62 
     | 
    
         
            +
                if (timeout_seconds == nil)
         
     | 
| 
       48 
63 
     | 
    
         
             
                  deadline = nil
         
     | 
| 
       49 
64 
     | 
    
         
             
                else
         
     | 
| 
       50 
     | 
    
         
            -
                  deadline = Time.now +  
     | 
| 
      
 65 
     | 
    
         
            +
                  deadline = Time.now + timeout_seconds
         
     | 
| 
       51 
66 
     | 
    
         
             
                end
         
     | 
| 
       52 
67 
     | 
    
         
             
                buf = ''
         
     | 
| 
       53 
68 
     | 
    
         
             
                unused_buf = '' if not unused_buf
         
     | 
| 
       54 
69 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                 
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                # STDOUT.puts "class=#{self.class}"
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                # Compatible hack. There are changes coming w.r.t. respond_to? for
         
     | 
| 
      
 70 
     | 
    
         
            +
                # XXX Compatible hack. There are changes coming w.r.t. respond_to? for
         
     | 
| 
       60 
71 
     | 
    
         
             
                # protected methods. Just do a simple poll, and see if it works.
         
     | 
| 
       61 
72 
     | 
    
         
             
                begin
         
     | 
| 
       62 
73 
     | 
    
         
             
                  result = IO.select([self], [], [], 0)
         
     | 
| 
       63 
74 
     | 
    
         
             
                  has_select = true;
         
     | 
| 
       64 
75 
     | 
    
         
             
                rescue Exception
         
     | 
| 
       65 
76 
     | 
    
         
             
                  has_select = false;
         
     | 
| 
       66 
     | 
    
         
            -
                  # STDOUT.puts "Exception: #{Exception}"
         
     | 
| 
       67 
77 
     | 
    
         
             
                end
         
     | 
| 
       68 
     | 
    
         
            -
                # STDOUT.puts "has_select=#{has_select}"
         
     | 
| 
       69 
78 
     | 
    
         | 
| 
       70 
79 
     | 
    
         
             
                begin
         
     | 
| 
       71 
     | 
    
         
            -
                  loop_count = loop_count + 1
         
     | 
| 
       72 
80 
     | 
    
         
             
                  # If it is possible to wait for data, then wait for data
         
     | 
| 
       73 
81 
     | 
    
         
             
                  t = (deadline ? (deadline - Time.now) : nil)
         
     | 
| 
       74 
82 
     | 
    
         
             
                  t = (t.nil? || t >= 0) ? t : 0
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # XXX If maxlen > unused_buf.length, then try to get more input?
         
     | 
| 
      
 84 
     | 
    
         
            +
                  #     Think about above. don't want to use up all of timeout.
         
     | 
| 
       75 
85 
     | 
    
         
             
                  if unused_buf.length == 0 && has_select && !IO.select([self], nil, nil, t)
         
     | 
| 
       76 
     | 
    
         
            -
                    # Timeout condition returns nil
         
     | 
| 
       77 
     | 
    
         
            -
                     
     | 
| 
      
 86 
     | 
    
         
            +
                    # Timeout condition from IO.select() returns nil
         
     | 
| 
      
 87 
     | 
    
         
            +
                    @pvout.print "parley,#{__LINE__}: TIMEOUT buf=\"#{buf}\"\n" if parley_verbose
         
     | 
| 
       78 
88 
     | 
    
         
             
                    timeout_handled = nil
         
     | 
| 
       79 
89 
     | 
    
         
             
                    result = nil
         
     | 
| 
       80 
     | 
    
         
            -
                    result = actions. 
     | 
| 
       81 
     | 
    
         
            -
                       
     | 
| 
       82 
     | 
    
         
            -
                      when :timeout
         
     | 
| 
      
 90 
     | 
    
         
            +
                    result = actions.find do|pattern, action|
         
     | 
| 
      
 91 
     | 
    
         
            +
                      if pattern == :timeout
         
     | 
| 
       83 
92 
     | 
    
         
             
                        timeout_handled = true
         
     | 
| 
       84 
     | 
    
         
            -
                        if  
     | 
| 
       85 
     | 
    
         
            -
                          /.*/.match(buf) #  
     | 
| 
       86 
     | 
    
         
            -
                          result = act[1].call(Regexp.last_match)
         
     | 
| 
      
 93 
     | 
    
         
            +
                        if action.respond_to?(:call)
         
     | 
| 
      
 94 
     | 
    
         
            +
                          r = action.call(/.*/.match(buf)) # call with entire buffer as a MatchData
         
     | 
| 
       87 
95 
     | 
    
         
             
                        else
         
     | 
| 
       88 
     | 
    
         
            -
                           
     | 
| 
      
 96 
     | 
    
         
            +
                          r = action
         
     | 
| 
       89 
97 
     | 
    
         
             
                        end
         
     | 
| 
       90 
     | 
    
         
            -
                         
     | 
| 
      
 98 
     | 
    
         
            +
                        @pvout.print "parley,#{__LINE__}: TIMEOUT Handled=\"#{r}\"\n" if parley_verbose
         
     | 
| 
      
 99 
     | 
    
         
            +
                        break r
         
     | 
| 
      
 100 
     | 
    
         
            +
                      else
         
     | 
| 
      
 101 
     | 
    
         
            +
                        nil
         
     | 
| 
       91 
102 
     | 
    
         
             
                      end
         
     | 
| 
       92 
103 
     | 
    
         
             
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
                    @pvout.print "parley,#{__LINE__}: TIMEOUT RESULT=\"#{result}\"\n" if parley_verbose
         
     | 
| 
       93 
105 
     | 
    
         
             
                    if (!timeout_handled)
         
     | 
| 
       94 
106 
     | 
    
         
             
                      # XXX need to prepend buf to @unusedbuf
         
     | 
| 
       95 
107 
     | 
    
         
             
                      unused_buf = buf  # save data for next time
         
     | 
| 
       96 
     | 
    
         
            -
                      raise "timeout" 
     | 
| 
      
 108 
     | 
    
         
            +
                      raise "timeout"
         
     | 
| 
       97 
109 
     | 
    
         
             
                    end
         
     | 
| 
       98 
     | 
    
         
            -
                    STDOUT.print "TIMEOUT RESULT=\"#{result}\"\n" if parley_verbose
         
     | 
| 
       99 
110 
     | 
    
         
             
                    return result unless result == :reset_timeout
         
     | 
| 
      
 111 
     | 
    
         
            +
                    matched = true
         
     | 
| 
       100 
112 
     | 
    
         
             
                  else
         
     | 
| 
       101 
113 
     | 
    
         | 
| 
       102 
114 
     | 
    
         
             
                    # We've waited, if that was possible, check for data present
         
     | 
| 
       103 
115 
     | 
    
         
             
                    if unused_buf.length == 0 && eof?
         
     | 
| 
       104 
     | 
    
         
            -
                       
     | 
| 
       105 
     | 
    
         
            -
                      result = nil
         
     | 
| 
      
 116 
     | 
    
         
            +
                      @pvout.print "parley,#{__LINE__}: EOF Buffer=\"#{buf}\"\n" if parley_verbose
         
     | 
| 
       106 
117 
     | 
    
         
             
                      eof_handled = false
         
     | 
| 
       107 
     | 
    
         
            -
                      actions. 
     | 
| 
       108 
     | 
    
         
            -
                        case  
     | 
| 
      
 118 
     | 
    
         
            +
                      result = actions.find do |pattern, action|
         
     | 
| 
      
 119 
     | 
    
         
            +
                        case pattern
         
     | 
| 
       109 
120 
     | 
    
         
             
                        when :eof
         
     | 
| 
       110 
121 
     | 
    
         
             
                          eof_handled = true
         
     | 
| 
       111 
     | 
    
         
            -
                          if  
     | 
| 
       112 
     | 
    
         
            -
                            /.*/m.match(buf) 
     | 
| 
       113 
     | 
    
         
            -
                            result = act[1].call(Regexp.last_match)
         
     | 
| 
      
 122 
     | 
    
         
            +
                          if action.respond_to?(:call)
         
     | 
| 
      
 123 
     | 
    
         
            +
                            result = action.call(/.*/m.match(buf))
         
     | 
| 
       114 
124 
     | 
    
         
             
                          else
         
     | 
| 
       115 
     | 
    
         
            -
                            result =  
     | 
| 
      
 125 
     | 
    
         
            +
                            result = action
         
     | 
| 
       116 
126 
     | 
    
         
             
                          end
         
     | 
| 
       117 
127 
     | 
    
         
             
                          break result
         
     | 
| 
      
 128 
     | 
    
         
            +
                        else
         
     | 
| 
      
 129 
     | 
    
         
            +
                          nil
         
     | 
| 
       118 
130 
     | 
    
         
             
                        end
         
     | 
| 
       119 
131 
     | 
    
         
             
                      end
         
     | 
| 
       120 
     | 
    
         
            -
                       
     | 
| 
      
 132 
     | 
    
         
            +
                      unless eof_handled
         
     | 
| 
       121 
133 
     | 
    
         
             
                        # XXX need to prepend buf to @unusedbuf
         
     | 
| 
       122 
134 
     | 
    
         
             
                        unused_buf = buf  # save data for next time
         
     | 
| 
       123 
     | 
    
         
            -
                        raise  
     | 
| 
      
 135 
     | 
    
         
            +
                        raise "End of file"
         
     | 
| 
       124 
136 
     | 
    
         
             
                      end
         
     | 
| 
       125 
137 
     | 
    
         
             
                      return result
         
     | 
| 
       126 
138 
     | 
    
         
             
                    end
         
     | 
| 
       127 
139 
     | 
    
         | 
| 
      
 140 
     | 
    
         
            +
                    # No timeout and no EOF. There is some input data to look at
         
     | 
| 
       128 
141 
     | 
    
         
             
                    # Greedy read:
         
     | 
| 
       129 
142 
     | 
    
         
             
                    # buf << self.read_nonblock(maxlen)
         
     | 
| 
       130 
143 
     | 
    
         
             
                    if (unused_buf.length > 0)
         
     | 
| 
         @@ -140,18 +153,18 @@ module Parley 
     | 
|
| 
       140 
153 
     | 
    
         
             
                    result = :continue
         
     | 
| 
       141 
154 
     | 
    
         
             
                    matched = false
         
     | 
| 
       142 
155 
     | 
    
         
             
                    result = actions.each_with_index do |act,i|
         
     | 
| 
       143 
     | 
    
         
            -
                      #  
     | 
| 
      
 156 
     | 
    
         
            +
                      # @pvout.print "parley,#{__LINE__}: buf=\"#{buf}\"\tact=#{act[0]}\n" if parley_verbose
         
     | 
| 
       144 
157 
     | 
    
         
             
                      m = case act[0]
         
     | 
| 
       145 
158 
     | 
    
         
             
                          when Regexp
         
     | 
| 
       146 
     | 
    
         
            -
                            act[0].match(buf) 
     | 
| 
      
 159 
     | 
    
         
            +
                            act[0].match(buf)
         
     | 
| 
       147 
160 
     | 
    
         
             
                          when String
         
     | 
| 
       148 
     | 
    
         
            -
                            act[0] = Regexp.new(act[0]) # caching the regexp conversion 
     | 
| 
       149 
     | 
    
         
            -
                            act[0].match(buf) 
     | 
| 
      
 161 
     | 
    
         
            +
                            act[0] = Regexp.new(act[0]) # caching the regexp conversion
         
     | 
| 
      
 162 
     | 
    
         
            +
                            act[0].match(buf)
         
     | 
| 
       150 
163 
     | 
    
         
             
                          else
         
     | 
| 
       151 
164 
     | 
    
         
             
                            nil
         
     | 
| 
       152 
165 
     | 
    
         
             
                          end
         
     | 
| 
       153 
166 
     | 
    
         
             
                      if m
         
     | 
| 
       154 
     | 
    
         
            -
                         
     | 
| 
      
 167 
     | 
    
         
            +
                        @pvout.print "parley,#{__LINE__}: match[#{i}]=\"#{buf}\"\n" if parley_verbose
         
     | 
| 
       155 
168 
     | 
    
         
             
                        matched = true
         
     | 
| 
       156 
169 
     | 
    
         
             
                        if act[1]
         
     | 
| 
       157 
170 
     | 
    
         
             
                          if act[1].respond_to?(:call)
         
     | 
| 
         @@ -164,7 +177,7 @@ module Parley 
     | 
|
| 
       164 
177 
     | 
    
         
             
                        end
         
     | 
| 
       165 
178 
     | 
    
         
             
                        buf = ''  # consume the buffer (XXX only the part that matched?)
         
     | 
| 
       166 
179 
     | 
    
         
             
                        # XXX if the regex had post context, don't consume that.
         
     | 
| 
       167 
     | 
    
         
            -
                         
     | 
| 
      
 180 
     | 
    
         
            +
                        @pvout.puts "parley,#{__LINE__}: result=#{result}" if parley_verbose
         
     | 
| 
       168 
181 
     | 
    
         
             
                        break result
         
     | 
| 
       169 
182 
     | 
    
         
             
                      end
         
     | 
| 
       170 
183 
     | 
    
         
             
                      result
         
     | 
| 
         @@ -172,25 +185,28 @@ module Parley 
     | 
|
| 
       172 
185 
     | 
    
         
             
                  end
         
     | 
| 
       173 
186 
     | 
    
         | 
| 
       174 
187 
     | 
    
         
             
                  if matched == true
         
     | 
| 
      
 188 
     | 
    
         
            +
                    @pvout.puts "parley,#{__LINE__}: MATCH, result=#{result}" if parley_verbose
         
     | 
| 
       175 
189 
     | 
    
         
             
                    result = case result
         
     | 
| 
       176 
190 
     | 
    
         
             
                             when :continue
         
     | 
| 
       177 
191 
     | 
    
         
             
                               :continue
         
     | 
| 
       178 
192 
     | 
    
         
             
                             when nil  # explicit end
         
     | 
| 
       179 
193 
     | 
    
         
             
                               break nil
         
     | 
| 
       180 
194 
     | 
    
         
             
                             when :reset_timeout
         
     | 
| 
       181 
     | 
    
         
            -
                               deadline = Time.now +  
     | 
| 
       182 
     | 
    
         
            -
                                
     | 
| 
      
 195 
     | 
    
         
            +
                               deadline = Time.now + timeout_seconds # XXX vs deadline in lambda closure?
         
     | 
| 
      
 196 
     | 
    
         
            +
                               @pvout.puts "parley,#{__LINE__}: deadline=#{deadline.to_s}, continue" if parley_verbose
         
     | 
| 
       183 
197 
     | 
    
         
             
                               :continue
         
     | 
| 
       184 
198 
     | 
    
         
             
                             else  # return with result
         
     | 
| 
       185 
199 
     | 
    
         
             
                               break result
         
     | 
| 
       186 
200 
     | 
    
         
             
                             end
         
     | 
| 
       187 
201 
     | 
    
         
             
                  else
         
     | 
| 
      
 202 
     | 
    
         
            +
                    @pvout.puts "parley,#{__LINE__}: no match, implicit :continue, buf=#{buf}" if parley_verbose
         
     | 
| 
       188 
203 
     | 
    
         
             
                    result = :continue
         
     | 
| 
       189 
204 
     | 
    
         
             
                  end
         
     | 
| 
       190 
205 
     | 
    
         
             
                end while result == :continue
         
     | 
| 
       191 
206 
     | 
    
         
             
              end
         
     | 
| 
       192 
207 
     | 
    
         
             
            end
         
     | 
| 
       193 
208 
     | 
    
         | 
| 
      
 209 
     | 
    
         
            +
            # Including the Parley module will monkey-patch the IO class
         
     | 
| 
       194 
210 
     | 
    
         
             
            class IO
         
     | 
| 
       195 
211 
     | 
    
         
             
              include Parley
         
     | 
| 
       196 
212 
     | 
    
         
             
            end
         
     | 
    
        data/parley.gemspec
    CHANGED
    
    | 
         @@ -5,24 +5,22 @@ 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       7 
7 
     | 
    
         
             
              s.name = "parley"
         
     | 
| 
       8 
     | 
    
         
            -
              s.version = "0. 
     | 
| 
      
 8 
     | 
    
         
            +
              s.version = "0.2.0"
         
     | 
| 
       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-02- 
     | 
| 
      
 12 
     | 
    
         
            +
              s.date = "2013-02-28"
         
     | 
| 
       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 = [
         
     | 
| 
       16 
16 
     | 
    
         
             
                "LICENSE.txt",
         
     | 
| 
       17 
     | 
    
         
            -
                "README.md" 
     | 
| 
       18 
     | 
    
         
            -
                "README.rdoc"
         
     | 
| 
      
 17 
     | 
    
         
            +
                "README.md"
         
     | 
| 
       19 
18 
     | 
    
         
             
              ]
         
     | 
| 
       20 
19 
     | 
    
         
             
              s.files = [
         
     | 
| 
       21 
20 
     | 
    
         
             
                ".document",
         
     | 
| 
       22 
21 
     | 
    
         
             
                "Gemfile",
         
     | 
| 
       23 
22 
     | 
    
         
             
                "LICENSE.txt",
         
     | 
| 
       24 
23 
     | 
    
         
             
                "README.md",
         
     | 
| 
       25 
     | 
    
         
            -
                "README.rdoc",
         
     | 
| 
       26 
24 
     | 
    
         
             
                "Rakefile",
         
     | 
| 
       27 
25 
     | 
    
         
             
                "VERSION",
         
     | 
| 
       28 
26 
     | 
    
         
             
                "lib/parley.rb",
         
     | 
| 
         @@ -33,7 +31,7 @@ Gem::Specification.new do |s| 
     | 
|
| 
       33 
31 
     | 
    
         
             
              s.homepage = "http://github.com/lzrd/parley"
         
     | 
| 
       34 
32 
     | 
    
         
             
              s.licenses = ["MIT"]
         
     | 
| 
       35 
33 
     | 
    
         
             
              s.require_paths = ["lib"]
         
     | 
| 
       36 
     | 
    
         
            -
              s.rubygems_version = "1.8. 
     | 
| 
      
 34 
     | 
    
         
            +
              s.rubygems_version = "1.8.25"
         
     | 
| 
       37 
35 
     | 
    
         
             
              s.summary = "An expect-like gem, modeled after Perl's Expect.pm"
         
     | 
| 
       38 
36 
     | 
    
         | 
| 
       39 
37 
     | 
    
         
             
              if s.respond_to? :specification_version then
         
     | 
    
        data/test/test_parley.rb
    CHANGED
    
    | 
         @@ -1,7 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0
         
     | 
| 
      
 3 
     | 
    
         
            +
            $LOAD_PATH.unshift("#{File.dirname(__FILE__)}") if __FILE__ == $0
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       1 
5 
     | 
    
         
             
            require 'helper'
         
     | 
| 
       2 
6 
     | 
    
         
             
            require "test/unit"
         
     | 
| 
       3 
7 
     | 
    
         
             
            require 'parley'
         
     | 
| 
       4 
8 
     | 
    
         
             
            require 'stringio'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'open3'
         
     | 
| 
       5 
10 
     | 
    
         | 
| 
       6 
11 
     | 
    
         
             
            #class TestParley < Test::Unit::TestCase
         
     | 
| 
       7 
12 
     | 
    
         
             
            #  should "probably rename this file and start testing for real" do
         
     | 
| 
         @@ -30,6 +35,16 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       30 
35 
     | 
    
         
             
                assert(result == :timeout, "** ERROR result = #{result}")
         
     | 
| 
       31 
36 
     | 
    
         
             
              end
         
     | 
| 
       32 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
              def test_single_match
         
     | 
| 
      
 39 
     | 
    
         
            +
                sin = StringIO.new(@text)
         
     | 
| 
      
 40 
     | 
    
         
            +
                result = sin.parley(0,
         
     | 
| 
      
 41 
     | 
    
         
            +
                                    [/apple/, "just apple"],
         
     | 
| 
      
 42 
     | 
    
         
            +
                                    [/white/, "1 too many matches"],
         
     | 
| 
      
 43 
     | 
    
         
            +
                                    [/dogs/, "2 too many matches"],
         
     | 
| 
      
 44 
     | 
    
         
            +
                                    [:eof, "very bad"])
         
     | 
| 
      
 45 
     | 
    
         
            +
                assert(result == "just apple", "Invalid result(#{result})")
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
       33 
48 
     | 
    
         
             
              def test_eof_constant
         
     | 
| 
       34 
49 
     | 
    
         
             
                io = File.new("/dev/null", "r")
         
     | 
| 
       35 
50 
     | 
    
         
             
                result = io.parley(20, [:eof, :eof])
         
     | 
| 
         @@ -52,8 +67,8 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       52 
67 
     | 
    
         
             
                                   ['three dogs', lambda{|m| count += 1; :continue }],
         
     | 
| 
       53 
68 
     | 
    
         
             
                                   [:eof, lambda{|m| count}] # XXX need to verify unused portion of buffer
         
     | 
| 
       54 
69 
     | 
    
         
             
                                  )
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
      
 70 
     | 
    
         
            +
                                  assert(count == 2, "** ERROR count = #{count}")
         
     | 
| 
      
 71 
     | 
    
         
            +
                                  assert(result == 2, "** ERROR result = #{result.inspect}")
         
     | 
| 
       57 
72 
     | 
    
         
             
              end
         
     | 
| 
       58 
73 
     | 
    
         | 
| 
       59 
74 
     | 
    
         
             
              def test_strings_maxread
         
     | 
| 
         @@ -65,8 +80,8 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       65 
80 
     | 
    
         
             
                                   ['three dogs', lambda{|m| count += 1; :continue }],
         
     | 
| 
       66 
81 
     | 
    
         
             
                                   [:eof, lambda{|m| count}] # XXX need to verify unused portion of buffer
         
     | 
| 
       67 
82 
     | 
    
         
             
                                  )
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
      
 83 
     | 
    
         
            +
                                  assert(count == 2, "** ERROR count = #{count}")
         
     | 
| 
      
 84 
     | 
    
         
            +
                                  assert(result == 2, "** ERROR result = #{result.inspect}")
         
     | 
| 
       70 
85 
     | 
    
         
             
              end
         
     | 
| 
       71 
86 
     | 
    
         | 
| 
       72 
87 
     | 
    
         
             
              def test_patterns
         
     | 
| 
         @@ -77,8 +92,8 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       77 
92 
     | 
    
         
             
                                   [Regexp.new(colors.join('|')), lambda{|m| count += 1; :continue}],
         
     | 
| 
       78 
93 
     | 
    
         
             
                                   [:eof, lambda{|m| count}] # XXX need to verify unused portion of buffer
         
     | 
| 
       79 
94 
     | 
    
         
             
                                  )
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
      
 95 
     | 
    
         
            +
                                  assert(count == 2, "** ERROR count = #{count}")
         
     | 
| 
      
 96 
     | 
    
         
            +
                                  assert(result == 2, "** ERROR result = #{result.inspect}")
         
     | 
| 
       82 
97 
     | 
    
         
             
              end
         
     | 
| 
       83 
98 
     | 
    
         | 
| 
       84 
99 
     | 
    
         
             
              #
         
     | 
| 
         @@ -95,8 +110,8 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       95 
110 
     | 
    
         
             
                                   [Regexp.new(colors.join('|')), lambda{|m| count += 1; :continue}],
         
     | 
| 
       96 
111 
     | 
    
         
             
                                   [:eof, lambda{|m| count}] # XXX need to verify unused portion of buffer
         
     | 
| 
       97 
112 
     | 
    
         
             
                                  )
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
      
 113 
     | 
    
         
            +
                                  assert(count == 1, "** ERROR count = #{count}")
         
     | 
| 
      
 114 
     | 
    
         
            +
                                  assert(result == 1, "** ERROR result = #{result.inspect}")
         
     | 
| 
       100 
115 
     | 
    
         
             
              end
         
     | 
| 
       101 
116 
     | 
    
         | 
| 
       102 
117 
     | 
    
         
             
              #
         
     | 
| 
         @@ -133,9 +148,9 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       133 
148 
     | 
    
         
             
                }
         
     | 
| 
       134 
149 
     | 
    
         
             
                ] # XXX need to verify unused portion of buffer
         
     | 
| 
       135 
150 
     | 
    
         
             
                                  )
         
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
      
 151 
     | 
    
         
            +
                                  assert(count == 3, "** ERROR count = #{count}")
         
     | 
| 
      
 152 
     | 
    
         
            +
                                  assert(result == 3, "** ERROR result = #{result.inspect}")
         
     | 
| 
      
 153 
     | 
    
         
            +
                                  # assert(buf_end.length > 0, "** Error buf_end.length=#{buf_end.length}, buf=#{buf_end}")
         
     | 
| 
       139 
154 
     | 
    
         
             
              end
         
     | 
| 
       140 
155 
     | 
    
         | 
| 
       141 
156 
     | 
    
         
             
              def test_empty_string
         
     | 
| 
         @@ -145,7 +160,7 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       145 
160 
     | 
    
         
             
                result = io.parley(0,
         
     | 
| 
       146 
161 
     | 
    
         
             
                                   [Regexp.new(colors.join('|')), lambda{|m| count += 1; :continue}],
         
     | 
| 
       147 
162 
     | 
    
         
             
                                   [:eof, lambda{|m| count}])
         
     | 
| 
       148 
     | 
    
         
            -
                assert(count == 0, "** ERROR count = #{ 
     | 
| 
      
 163 
     | 
    
         
            +
                assert(count == 0, "** ERROR count = #{count.inspect}")
         
     | 
| 
       149 
164 
     | 
    
         
             
                assert(result == 0, "** ERROR result = #{result.inspect}")
         
     | 
| 
       150 
165 
     | 
    
         
             
              end
         
     | 
| 
       151 
166 
     | 
    
         | 
| 
         @@ -176,25 +191,25 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       176 
191 
     | 
    
         
             
                             [/> /, lambda {|m| w_f.puts("cd pub/ruby"); nil }]
         
     | 
| 
       177 
192 
     | 
    
         
             
                            )
         
     | 
| 
       178 
193 
     | 
    
         | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
      
 194 
     | 
    
         
            +
                            # >
         
     | 
| 
      
 195 
     | 
    
         
            +
                            #  dir\n
         
     | 
| 
      
 196 
     | 
    
         
            +
                            r_f.parley(ftp_to, ["> ", lambda {|m| w_f.print "dir\r"}])
         
     | 
| 
       182 
197 
     | 
    
         | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
             
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
      
 198 
     | 
    
         
            +
                            # lrwxrwxrwx 1 1014 100 27 Feb 18 12:52 ruby-1.8.7-p334.tar.bz2 -> 1.8/ruby-1.8.7-p334.tar.bz2
         
     | 
| 
      
 199 
     | 
    
         
            +
                            r_f.parley(ftp_to,
         
     | 
| 
      
 200 
     | 
    
         
            +
                                       [/^ftp> /, lambda {|m|
         
     | 
| 
      
 201 
     | 
    
         
            +
                              for x in m.pre_match.split("\n")
         
     | 
| 
      
 202 
     | 
    
         
            +
                                if x =~ /(ruby.*?\.tar\.gz)/ then
         
     | 
| 
      
 203 
     | 
    
         
            +
                                  fnames.push $1
         
     | 
| 
      
 204 
     | 
    
         
            +
                                end
         
     | 
| 
      
 205 
     | 
    
         
            +
                              end
         
     | 
| 
      
 206 
     | 
    
         
            +
                              begin
         
     | 
| 
      
 207 
     | 
    
         
            +
                                w_f.print "quit\n"
         
     | 
| 
      
 208 
     | 
    
         
            +
                              rescue
         
     | 
| 
      
 209 
     | 
    
         
            +
                              end
         
     | 
| 
      
 210 
     | 
    
         
            +
                              :nil
         
     | 
| 
      
 211 
     | 
    
         
            +
                            }],
         
     | 
| 
      
 212 
     | 
    
         
            +
                              [:eof, nil])
         
     | 
| 
       198 
213 
     | 
    
         
             
                end
         
     | 
| 
       199 
214 
     | 
    
         
             
                puts "The latest ruby interpreter is #{fnames.sort.pop}"
         
     | 
| 
       200 
215 
     | 
    
         
             
              end
         
     | 
| 
         @@ -203,11 +218,110 @@ class TestIO < Test::Unit::TestCase 
     | 
|
| 
       203 
218 
     | 
    
         
             
                read, write, pid = PTY.spawn(
         
     | 
| 
       204 
219 
     | 
    
         
             
                  # XXX fire off a ruby program, not bash, to get the test behavoir we want
         
     | 
| 
       205 
220 
     | 
    
         
             
                  '/bin/bash -x -c "for x in wait done too_late; do sleep 3; echo $x; done"')
         
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
      
 221 
     | 
    
         
            +
                  read.parley_verbose = true if @test_verbose
         
     | 
| 
      
 222 
     | 
    
         
            +
                  result = read.parley(5,
         
     | 
| 
      
 223 
     | 
    
         
            +
                                       [/wait/, :reset_timeout],
         
     | 
| 
      
 224 
     | 
    
         
            +
                                       [/done/, :pass ],
         
     | 
| 
      
 225 
     | 
    
         
            +
                                       [:timeout, :timeout])
         
     | 
| 
      
 226 
     | 
    
         
            +
                  assert(result == :pass, "** ERROR result = #{result}")
         
     | 
| 
      
 227 
     | 
    
         
            +
              end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
              def test_guessing_game
         
     | 
| 
      
 230 
     | 
    
         
            +
                @NGAMES = 2
         
     | 
| 
      
 231 
     | 
    
         
            +
                @UPPER_LIMIT = 100
         
     | 
| 
      
 232 
     | 
    
         
            +
                @UPPER_LIMIT_LOG2 = 8
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                game = <<-GUESSING_GAME_EOT
         
     | 
| 
      
 235 
     | 
    
         
            +
                  BEGIN {puts "0>"; @n = 0}
         
     | 
| 
      
 236 
     | 
    
         
            +
                  END { puts "Goodbye!"; }
         
     | 
| 
      
 237 
     | 
    
         
            +
                  @secret ||= rand 100
         
     | 
| 
      
 238 
     | 
    
         
            +
                  g = $F[0] ? $F[0].strip : ""
         
     | 
| 
      
 239 
     | 
    
         
            +
                  z = "?"
         
     | 
| 
      
 240 
     | 
    
         
            +
                  if g =~ /\\d+$/m
         
     | 
| 
      
 241 
     | 
    
         
            +
                    z = (g.to_i <=> @secret)
         
     | 
| 
      
 242 
     | 
    
         
            +
                    case g.to_i <=> @secret
         
     | 
| 
      
 243 
     | 
    
         
            +
                    when -1
         
     | 
| 
      
 244 
     | 
    
         
            +
                      puts "too low"
         
     | 
| 
      
 245 
     | 
    
         
            +
                    when 1
         
     | 
| 
      
 246 
     | 
    
         
            +
                      puts "too high"
         
     | 
| 
      
 247 
     | 
    
         
            +
                    when 0
         
     | 
| 
      
 248 
     | 
    
         
            +
                      puts "correct!"
         
     | 
| 
      
 249 
     | 
    
         
            +
                      @secret = rand 100
         
     | 
| 
      
 250 
     | 
    
         
            +
                      puts "Ready";
         
     | 
| 
      
 251 
     | 
    
         
            +
                    end
         
     | 
| 
      
 252 
     | 
    
         
            +
                  else
         
     | 
| 
      
 253 
     | 
    
         
            +
                    exit 0 if $F[0] == "exit"
         
     | 
| 
      
 254 
     | 
    
         
            +
                  end
         
     | 
| 
      
 255 
     | 
    
         
            +
                  @n += 1
         
     | 
| 
      
 256 
     | 
    
         
            +
                  puts "\#{@n}>"
         
     | 
| 
      
 257 
     | 
    
         
            +
                GUESSING_GAME_EOT
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
                # DRY: common code for sending a guess
         
     | 
| 
      
 260 
     | 
    
         
            +
                def sendguess resend = false
         
     | 
| 
      
 261 
     | 
    
         
            +
                  @myguess = ((@min + @max) / 2).to_i
         
     | 
| 
      
 262 
     | 
    
         
            +
                  puts "Resending guess" if resend
         
     | 
| 
      
 263 
     | 
    
         
            +
                  puts "Guessing #{@myguess}"
         
     | 
| 
      
 264 
     | 
    
         
            +
                  @sin.puts @myguess
         
     | 
| 
      
 265 
     | 
    
         
            +
                  @guesses += 1 unless resend
         
     | 
| 
      
 266 
     | 
    
         
            +
                  if @guesses > @UPPER_LIMIT_LOG2
         
     | 
| 
      
 267 
     | 
    
         
            +
                    "I Lost"  # Bug in program if we haven't guessed it already
         
     | 
| 
      
 268 
     | 
    
         
            +
                  else
         
     | 
| 
      
 269 
     | 
    
         
            +
                    :continue
         
     | 
| 
      
 270 
     | 
    
         
            +
                  end
         
     | 
| 
      
 271 
     | 
    
         
            +
                end
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
                def newgame
         
     | 
| 
      
 274 
     | 
    
         
            +
                  @min = 0
         
     | 
| 
      
 275 
     | 
    
         
            +
                  @max = @UPPER_LIMIT
         
     | 
| 
      
 276 
     | 
    
         
            +
                  @guesses = 0
         
     | 
| 
      
 277 
     | 
    
         
            +
                end
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
                def winner
         
     | 
| 
      
 280 
     | 
    
         
            +
                  puts "I win!"
         
     | 
| 
      
 281 
     | 
    
         
            +
                  @wins += 1
         
     | 
| 
      
 282 
     | 
    
         
            +
                  newgame
         
     | 
| 
      
 283 
     | 
    
         
            +
                  (@games -= 1) > 0 ? sendguess : "finished" # :continue or "finished"
         
     | 
| 
      
 284 
     | 
    
         
            +
                end
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
                @games = @NGAMES
         
     | 
| 
      
 287 
     | 
    
         
            +
                @wins = 0
         
     | 
| 
      
 288 
     | 
    
         
            +
                # puts "Running: ruby -n -a -e #{game}"
         
     | 
| 
      
 289 
     | 
    
         
            +
                result = nil
         
     | 
| 
      
 290 
     | 
    
         
            +
                pty_return = PTY.spawn('ruby', '-n', '-a', '-e', game) do |sout, sin, pid|
         
     | 
| 
      
 291 
     | 
    
         
            +
                  @sin = sin
         
     | 
| 
      
 292 
     | 
    
         
            +
                  puts "Sending <CR>"
         
     | 
| 
      
 293 
     | 
    
         
            +
                  sin.puts '' # Elicit a prompt from the game
         
     | 
| 
      
 294 
     | 
    
         
            +
                  r = select([sout], [], [], 2)  # Wait up to 15 seconds for output from guessing game
         
     | 
| 
      
 295 
     | 
    
         
            +
                  puts "Wokeup from select with <<#{r.inspect}>>"
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
                  newgame
         
     | 
| 
      
 298 
     | 
    
         
            +
                  @n_to_reset = 0
         
     | 
| 
      
 299 
     | 
    
         
            +
                  sout.parley_maxread = 100
         
     | 
| 
      
 300 
     | 
    
         
            +
                  # sout.parley_verbose = true
         
     | 
| 
      
 301 
     | 
    
         
            +
                  result = sout.parley(
         
     | 
| 
      
 302 
     | 
    
         
            +
                    2,
         
     | 
| 
      
 303 
     | 
    
         
            +
                    [/too low/, lambda{|m| @min = @myguess + 1; sendguess}],
         
     | 
| 
      
 304 
     | 
    
         
            +
                    [/too high/, lambda{|m| @max = @myguess - 1; sendguess}],
         
     | 
| 
      
 305 
     | 
    
         
            +
                    [/correct/, lambda{|m| winner}],
         
     | 
| 
      
 306 
     | 
    
         
            +
                    [/>/, lambda{|m| sendguess true}],
         
     | 
| 
      
 307 
     | 
    
         
            +
                    [
         
     | 
| 
      
 308 
     | 
    
         
            +
                      :timeout,
         
     | 
| 
      
 309 
     | 
    
         
            +
                      lambda do |m|
         
     | 
| 
      
 310 
     | 
    
         
            +
                        sin.puts ""
         
     | 
| 
      
 311 
     | 
    
         
            +
                        @n_to_reset += 1
         
     | 
| 
      
 312 
     | 
    
         
            +
                        puts "Resetting timeout #{@n_to_reset}"
         
     | 
| 
      
 313 
     | 
    
         
            +
                        if @n_to_reset > 2 
         
     | 
| 
      
 314 
     | 
    
         
            +
                          sin.puts "exit"
         
     | 
| 
      
 315 
     | 
    
         
            +
                          "Timeout"
         
     | 
| 
      
 316 
     | 
    
         
            +
                        else
         
     | 
| 
      
 317 
     | 
    
         
            +
                          :reset_timeout
         
     | 
| 
      
 318 
     | 
    
         
            +
                        end
         
     | 
| 
      
 319 
     | 
    
         
            +
                      end
         
     | 
| 
      
 320 
     | 
    
         
            +
                  ])
         
     | 
| 
      
 321 
     | 
    
         
            +
                end
         
     | 
| 
      
 322 
     | 
    
         
            +
                puts "Script finished, pty_return=#{pty_return}"
         
     | 
| 
      
 323 
     | 
    
         
            +
                assert(result == "finished", "didn't win last game")
         
     | 
| 
      
 324 
     | 
    
         
            +
                # assert(ec == 0, "Bad exit from guessing game")
         
     | 
| 
      
 325 
     | 
    
         
            +
                assert(@wins == @NGAMES, "Didn't win exactly #{@NGAMES} games")
         
     | 
| 
       212 
326 
     | 
    
         
             
              end
         
     | 
| 
       213 
327 
     | 
    
         
             
            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. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.0
         
     | 
| 
       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-02- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2013-02-28 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: rdoc
         
     | 
| 
         @@ -66,13 +66,11 @@ extensions: [] 
     | 
|
| 
       66 
66 
     | 
    
         
             
            extra_rdoc_files:
         
     | 
| 
       67 
67 
     | 
    
         
             
            - LICENSE.txt
         
     | 
| 
       68 
68 
     | 
    
         
             
            - README.md
         
     | 
| 
       69 
     | 
    
         
            -
            - README.rdoc
         
     | 
| 
       70 
69 
     | 
    
         
             
            files:
         
     | 
| 
       71 
70 
     | 
    
         
             
            - .document
         
     | 
| 
       72 
71 
     | 
    
         
             
            - Gemfile
         
     | 
| 
       73 
72 
     | 
    
         
             
            - LICENSE.txt
         
     | 
| 
       74 
73 
     | 
    
         
             
            - README.md
         
     | 
| 
       75 
     | 
    
         
            -
            - README.rdoc
         
     | 
| 
       76 
74 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       77 
75 
     | 
    
         
             
            - VERSION
         
     | 
| 
       78 
76 
     | 
    
         
             
            - lib/parley.rb
         
     | 
| 
         @@ -94,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       94 
92 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       95 
93 
     | 
    
         
             
                  segments:
         
     | 
| 
       96 
94 
     | 
    
         
             
                  - 0
         
     | 
| 
       97 
     | 
    
         
            -
                  hash: - 
     | 
| 
      
 95 
     | 
    
         
            +
                  hash: -3112653461861631076
         
     | 
| 
       98 
96 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       99 
97 
     | 
    
         
             
              none: false
         
     | 
| 
       100 
98 
     | 
    
         
             
              requirements:
         
     | 
| 
         @@ -103,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       103 
101 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       104 
102 
     | 
    
         
             
            requirements: []
         
     | 
| 
       105 
103 
     | 
    
         
             
            rubyforge_project: 
         
     | 
| 
       106 
     | 
    
         
            -
            rubygems_version: 1.8. 
     | 
| 
      
 104 
     | 
    
         
            +
            rubygems_version: 1.8.25
         
     | 
| 
       107 
105 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       108 
106 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       109 
107 
     | 
    
         
             
            summary: An expect-like gem, modeled after Perl's Expect.pm
         
     | 
    
        data/README.rdoc
    DELETED
    
    | 
         @@ -1,35 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            = parley
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            An Expect-like gem for Ruby
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            Parley is an implementation of an expect-like API.  It is designed to
         
     | 
| 
       6 
     | 
    
         
            -
            help port away from Perl Expect based applications.  The name "expect"
         
     | 
| 
       7 
     | 
    
         
            -
            is already well established in ruby.  Those of you who have wrestled
         
     | 
| 
       8 
     | 
    
         
            -
            with the interactive, text-mode, APIs of the world will appreciate the
         
     | 
| 
       9 
     | 
    
         
            -
            meaning of the word:
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            From http://www.thefreedictionary.com/parley "A discussion or conference, especially one between enemies over terms of truce or other matters."
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            See http://www.nist.gov/el/msid/expect.cfm for references to the original Expect language based on Tcl.
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            See http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod for information on Expect.pm
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
            == Known Issues
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
            * need to generatate adequte documentation. See test/test_parley.rb for now
         
     | 
| 
       20 
     | 
    
         
            -
            * :restart_timeout from IO::parley() doesn't have the desired effect
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
            == Contributing to parley
         
     | 
| 
       23 
     | 
    
         
            -
             
         
     | 
| 
       24 
     | 
    
         
            -
            * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
         
     | 
| 
       25 
     | 
    
         
            -
            * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
         
     | 
| 
       26 
     | 
    
         
            -
            * Fork the project.
         
     | 
| 
       27 
     | 
    
         
            -
            * Start a feature/bugfix branch.
         
     | 
| 
       28 
     | 
    
         
            -
            * Commit and push until you are happy with your contribution.
         
     | 
| 
       29 
     | 
    
         
            -
            * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
         
     | 
| 
       30 
     | 
    
         
            -
            * 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.
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
            == Copyright
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
            Copyright (c) 2013 Ben Stoltz.
         
     | 
| 
       35 
     | 
    
         
            -
            See LICENSE.txt for further details.
         
     |