scriptty 1.1.0-java → 1.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -29,13 +29,17 @@ module ScripTTY
29
29
  class Expect
30
30
 
31
31
  # Methods to export to Evaluator
32
- EXPORTED_METHODS = Set.new [:basedir, :init_term, :term, :connect, :screen, :expect, :on, :wait, :send, :send_password, :capture, :match, :push_patterns, :pop_patterns, :exit, :eval_script_file, :eval_script_inline, :sleep, :set_basedir, :set_timeout, :load_screens, :print, :puts, :p, :pp ]
32
+ EXPORTED_METHODS = Set.new [:basedir, :init_term, :term, :connect, :screen, :expect, :on, :wait, :send, :send_password, :capture, :match, :push_patterns, :pop_patterns, :exit, :eval_script_file, :eval_script_inline, :sleep, :set_basedir, :set_timeout, :load_screens, :matched_screen, :matched_pattern, :print, :puts, :p, :pp ]
33
33
 
34
34
  attr_reader :term # The terminal emulation object
35
35
 
36
36
  attr_reader :capture # The last non-background captured fields. For a ScreenPattern match, this is a Hash of fields. For a String or Regexp match, this is a MatchData object.
37
37
  alias match capture # "match" is the deprecated name for "capture"
38
38
 
39
+ attr_accessor :matched_pattern # The last non-background pattern that matched (might be a RegExp or a ScreenPattern)
40
+
41
+ attr_accessor :matched_screen # The last non-background ScreenPattern that matched.
42
+
39
43
  attr_accessor :transcript_writer # Set this to an instance of ScripTTY::Util::Transcript::Writer
40
44
  attr_accessor :transcript_writer_autoclose # Set this to false to disable closing transcript_writer on exit
41
45
 
@@ -58,6 +62,8 @@ module ScripTTY
58
62
  @transcript_writer_autoclose = options[:transcript_writer_autoclose].nil? ? true : options[:transcript_writer_autoclose]
59
63
  @screen_patterns = {}
60
64
  @basedir = "."
65
+ @matched_pattern = nil
66
+ @matched_screen = nil
61
67
  end
62
68
 
63
69
  # Get instance variable from the Evaluator
@@ -87,20 +93,10 @@ module ScripTTY
87
93
  nil
88
94
  end
89
95
 
90
- # Return the expanded path relative to basedir
91
- def expand_path(path)
92
- base = Pathname.new(@basedir)
93
- p = Pathname.new(path)
94
- unless p.absolute?
95
- p = base.join(p)
96
- end
97
- p.expand_path.to_s
98
- end
99
-
100
96
  # Load and evaluate a script from a file.
101
97
  def eval_script_file(path)
102
98
  fail_unexpected_block if block_given?
103
- path = expand_path(path)
99
+ path = File.expand_path(path, @basedir)
104
100
  eval_script_inline(File.read(path), path)
105
101
  end
106
102
 
@@ -200,7 +196,7 @@ module ScripTTY
200
196
  fail_unexpected_block if block_given?
201
197
  filenames_or_glob = filenames_or_glob.to_s if filenames_or_glob.is_a?(Pathname)
202
198
  if filenames_or_glob.is_a?(String)
203
- filenames_or_glob = expand_path(filenames_or_glob)
199
+ filenames_or_glob = File.expand_path(filenames_or_glob, @basedir)
204
200
  filenames = Dir.glob(filenames_or_glob)
205
201
  elsif filenames_or_glob.is_a?(Array)
206
202
  filenames = filenames_or_glob
@@ -208,7 +204,7 @@ module ScripTTY
208
204
  raise ArgumentError.new("load_screens takes a string(glob) or an array, not #{filenames.class.name}")
209
205
  end
210
206
  filenames.each do |filename|
211
- ScreenPattern.parse(File.read(filename)).each do |pattern|
207
+ ScreenPattern.parse(File.read(filename), filename).each do |pattern|
212
208
  @screen_patterns[pattern.name.to_sym] = pattern
213
209
  end
214
210
  end
@@ -441,6 +437,8 @@ module ScripTTY
441
437
 
442
438
  # Make the next wait() call return
443
439
  unless ph.background?
440
+ @matched_pattern = ph.pattern
441
+ @matched_screen = ph.pattern if ph.pattern.is_a?(ScreenPattern)
444
442
  @capture = m
445
443
  @wait_finished = true
446
444
  @net.suspend
@@ -33,6 +33,9 @@ module ScripTTY
33
33
  # RequestDispatcher can be used, for example, to provide an HTTP interface to
34
34
  # functions of a screen-scraped terminal.
35
35
  class RequestDispatcher
36
+
37
+ class RequestCancelled < StandardError; end
38
+
36
39
  def initialize
37
40
  # Graceful shutdown flag
38
41
  @finishing_lock = Mutex.new
@@ -117,18 +120,27 @@ module ScripTTY
117
120
  def main
118
121
  loop do
119
122
  break if finishing?
120
- begin
121
- handle_one_request
122
- rescue => exc
123
- # Log & swallow exception
124
- show_exception(exc)
125
- close_expect rescue nil # Ignore errors while closing the connection
126
- sleep 0.5 # Delay just a tiny bit to keep an exception loop from consuming all available resources.
127
- end
123
+ wrap_in_exception_handler(
124
+ :body => Proc.new {
125
+ handle_one_request
126
+ },
127
+ :rescue => Proc.new { |exc|
128
+ # Log & swallow exception
129
+ show_exception(exc)
130
+ close_expect rescue nil # Ignore errors while closing the connection
131
+ sleep 0.5 # Delay just a tiny bit to keep an exception loop from consuming all available resources.
132
+ }
133
+ )
128
134
  end
129
135
  execute_hooks(:before_finish)
130
136
  ensure
131
137
  close_expect
138
+
139
+ # Clean up any remaining requests.
140
+ while (request = dequeue)
141
+ request[:exception] = RequestCancelled.new("main loop exited; request not executed")
142
+ signal_request_done(request)
143
+ end
132
144
  end
133
145
 
134
146
  def handle_one_request
@@ -140,22 +152,36 @@ module ScripTTY
140
152
 
141
153
  # Run the before_each_request hooks. If an exception is raised,
142
154
  # put the request back on the queue before re-raising the error.
143
- begin
144
- execute_hooks(:before_each_request)
145
- rescue
146
- requeue(request)
147
- raise
148
- end
155
+ wrap_in_exception_handler(
156
+ :body => Proc.new {
157
+ execute_hooks(:before_each_request)
158
+ },
159
+ :rescue => Proc.new { |exc|
160
+ requeue(request)
161
+ },
162
+ :reraise => true
163
+ )
149
164
 
150
165
  # Execute the request
166
+ success = false
167
+ exception_caught = false
151
168
  begin
152
- request[:result] = block_eval(request[:block_how], &request[:block])
153
- rescue => exc
154
- show_exception(exc, "in request")
155
- request[:exception] = exc
156
- close_expect rescue nil
169
+ wrap_in_exception_handler(
170
+ :body => Proc.new {
171
+ request[:result] = block_eval(request[:block_how], &request[:block])
172
+ success = true
173
+ },
174
+ :rescue => Proc.new { |exc|
175
+ show_exception(exc, "in request")
176
+ request[:exception] = exc
177
+ close_expect rescue nil
178
+ exception_caught = true
179
+ }
180
+ )
181
+ ensure
182
+ signal_request_done(request)
183
+ raise "RUBY BUG: No success and no exception caught: #{$ERROR_INFO.inspect}" unless success or exception_caught
157
184
  end
158
- request[:cv_mutex].synchronize { request[:cv].signal }
159
185
 
160
186
  # Execute the after_each_request hooks.
161
187
  execute_hooks(:after_each_request)
@@ -235,7 +261,32 @@ module ScripTTY
235
261
  output = ["Exception #{context || "in #{self}"}: #{exc} (#{exc.class.name})"]
236
262
  output += exc.backtrace.map { |line| " #{line}" }
237
263
  $stderr.puts output.join("\n")
238
- true # true means to re-raise the exception
264
+ end
265
+
266
+ def signal_request_done(request)
267
+ request[:cv_mutex].synchronize { request[:cv].signal }
268
+ end
269
+
270
+ # XXX - Workaround for JRuby bug.
271
+ #
272
+ # Apparently, if we do this:
273
+ #
274
+ # begin
275
+ # # some code here
276
+ # rescue Exception => exc
277
+ # # handle
278
+ # end
279
+ #
280
+ # Then other errors like SyntaxError and ArgumentError don't get caught
281
+ # when we do our block-passing-over-threads magic. However, if we
282
+ # enumerate a bunch of exception classes, it seems to work.
283
+ def wrap_in_exception_handler(options={})
284
+ begin
285
+ options[:body].call
286
+ rescue Exception, ScriptError, SystemStackError, StandardError => exc
287
+ options[:rescue].call(exc) if options[:rescue]
288
+ raise if options[:reraise]
289
+ end
239
290
  end
240
291
  end
241
292
  end
@@ -59,19 +59,20 @@ module ScripTTY
59
59
  RECOGNIZED_PROPERTIES = SINGLE_CHAR_PROPERTIES + TWO_TUPLE_PROPERTIES + %w( rectangle fields text )
60
60
 
61
61
  class <<self
62
- def parse(s, &block)
63
- new(s, &block).parse
62
+ def parse(s, filename=nil, lineno=nil, &block)
63
+ new(s, filename, lineno, &block).parse
64
64
  nil
65
65
  end
66
66
  protected :new # Users should not instantiate this object directly
67
67
  end
68
68
 
69
- def initialize(s, &block)
69
+ def initialize(s, filename=nil, lineno=nil, &block)
70
70
  raise ArgumentError.new("no block given") unless block
71
71
  @block = block
72
72
  @lines = preprocess(s).split("\n").map{|line| "#{line}\n"}
73
73
  @line = nil
74
- @lineno = 0
74
+ @filename = filename
75
+ @lineno = (lineno||1) - 1
75
76
  @state = :start
76
77
  end
77
78
 
@@ -529,7 +530,8 @@ module ScripTTY
529
530
 
530
531
  def parse_fail(message=nil, line=nil)
531
532
  line ||= @lineno
532
- raise ArgumentError.new("error:line #{line}: #{message || 'parse error'}")
533
+ f = @filename ? "#{@filename}:" : "line "
534
+ raise ArgumentError.new("error:#{f}#{line}: #{message || 'parse error'}")
533
535
  end
534
536
 
535
537
  # Pre-process an input string.
@@ -20,9 +20,9 @@ module ScripTTY
20
20
  class ScreenPattern
21
21
  class <<self
22
22
  # Parse a pattern file and return an array of ScreenPattern objects
23
- def parse(s)
23
+ def parse(s, filename=nil, lineno=nil)
24
24
  retval = []
25
- Parser.parse(s) do |spec|
25
+ Parser.parse(s, filename, lineno) do |spec|
26
26
  retval << new(spec[:name], spec[:properties])
27
27
  end
28
28
  retval
@@ -0,0 +1,76 @@
1
+ # = Tests for ScripTTY::RequestDispatcher
2
+ # Copyright (C) 2010 Infonium Inc.
3
+ #
4
+ # This file is part of ScripTTY.
5
+ #
6
+ # ScripTTY is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # ScripTTY is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with ScripTTY. If not, see <http://www.gnu.org/licenses/>.
18
+ require File.dirname(__FILE__) + "/test_helper.rb"
19
+ require 'scriptty/request_dispatcher'
20
+
21
+ class RequestDispatcherTest < Test::Unit::TestCase
22
+
23
+ if !defined?(Java)
24
+ # This test gets executed when JRuby is not detected
25
+ def test_dummy_no_jruby
26
+ raise LoadError.new("Cannot test ScripTTY::RequestDispatcher: Not running under JRuby")
27
+ end
28
+
29
+ else # defined?(Java)
30
+
31
+ def setup
32
+ @r = ScripTTY::RequestDispatcher.new
33
+ end
34
+
35
+ def teardown
36
+ @r.finish
37
+ end
38
+
39
+ def test_after_init
40
+ after_init_ran = false
41
+ @r.after_init { after_init_ran = true }
42
+ @r.start
43
+ sleep 0.2 # XXX - race condition
44
+ assert after_init_ran, "after_init hook should run"
45
+ end
46
+
47
+ def test_request
48
+ @r.start
49
+ assert_equal :success, @r.request { init_term "dg410"; :success }
50
+ end
51
+
52
+ def test_standard_exception_in_request
53
+ @r.instance_eval do
54
+ def show_exception(*args) end # Silence exceptions
55
+ end
56
+
57
+ @r.start
58
+ assert_raise ArgumentError do
59
+ @r.request { raise ArgumentError.new("foo") }
60
+ end
61
+ end
62
+
63
+ def test_base_exception_in_request
64
+ @r.instance_eval do
65
+ def show_exception(*args) end # Silence exceptions
66
+ end
67
+
68
+ @r.start
69
+ assert_raise SyntaxError do
70
+ @r.request { eval("*") }
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 1.1.0
9
+ version: 1.2.0
10
10
  platform: java
11
11
  authors:
12
12
  - Dwayne Litzenberger
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-13 00:00:00 -04:00
17
+ date: 2010-05-15 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -119,6 +119,7 @@ files:
119
119
  - test/fsm_test.rb
120
120
  - test/multiline_buffer_test.rb
121
121
  - test/net/event_loop_test.rb
122
+ - test/request_dispatcher_test.rb
122
123
  - test/screen_pattern/generator_test.rb
123
124
  - test/screen_pattern/parser_test.rb
124
125
  - test/screen_pattern/parser_test/explicit_cursor_pattern.txt
@@ -172,6 +173,7 @@ test_files:
172
173
  - test/fsm_definition_parser_test.rb
173
174
  - test/fsm_test.rb
174
175
  - test/multiline_buffer_test.rb
176
+ - test/request_dispatcher_test.rb
175
177
  - test/test_helper.rb
176
178
  - test/apps/capture_app_test.rb
177
179
  - test/apps/transcript_parse_app_test.rb