rspec-interactive 0.9.6 → 0.9.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 448fb430c0970d2d6f3dc12a3a1b6577dde234516d0d7f3fdccc735be784919b
4
- data.tar.gz: 650d41f575295fb43d1c97930ae49e4a7fe34aac1d4cb1ca2a7d3fe6a1cb25c6
3
+ metadata.gz: c87a284feb4bf76bac68cda8cbe5703a66f04a856c8e2aed9e27d30b89e2654e
4
+ data.tar.gz: 9336d2bff3ba1973921f8d7ba6a36d88bc11d4acd1c2b2ee86d7c47cb58d0356
5
5
  SHA512:
6
- metadata.gz: d5a4b51199209d0d248e1fc26a2d7e3cb4abf993eb2a61775162eda5107a2a97529bdd58867cb1e870a9c10f9da7c3ef60ce0ccd4ad484f6f900f9c2b0708a6f
7
- data.tar.gz: f57523af399e9ca55303101479fbc0940c60095a0ffe93a2092255954fe5be3003bfc82c41c7a416df72a12d72fd4aae0d578b5d7f6da85c1385a9f620950227
6
+ metadata.gz: 36afe559f97bc7cdee9e6833655f23e6092004b800e53beed28099afb8db6ce5511bc8177c9cc648ffc0a558bd221ca2ff13c5ff44e76132c20af99b30281fda
7
+ data.tar.gz: '097084b7f1fec026f08433a8d12d56997b83a8deb8852026fc04dc1f3e7ec5410433e0758b374724cb2b5450f7b5be4e4db2d9953241a7bbd703f610f032e6ef'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-interactive (0.9.5)
4
+ rspec-interactive (0.9.8)
5
5
  listen
6
6
  pry
7
7
  rspec-core
@@ -17,6 +17,13 @@ module RSpec
17
17
  @client.print(str.to_s + "\n")
18
18
  end
19
19
 
20
+ def flush
21
+ end
22
+
23
+ def closed?
24
+ @client.closed?
25
+ end
26
+
20
27
  def string
21
28
  @output
22
29
  end
@@ -4,7 +4,7 @@ class Pry
4
4
  alias_method :old_eval, :eval
5
5
 
6
6
  def eval(line, options = {})
7
- RSpec::Interactive.eval do
7
+ RSpec::Interactive.eval(line, options) do
8
8
  old_eval(line, options)
9
9
  end
10
10
  end
@@ -1,52 +1,13 @@
1
1
  module RSpec
2
2
  module Interactive
3
3
  class Stdio
4
- def self.capture2(stdout:, stderr:)
4
+ def self.capture(stdout:, stderr:)
5
5
  old_stdout, old_stderr = $stdout, $stderr
6
6
  $stdout, $stderr = stdout, stderr
7
7
  yield
8
8
  ensure
9
9
  $stdout, $stderr = old_stdout, old_stderr
10
10
  end
11
-
12
- def self.capture(stdout:, stderr:)
13
- raise ArgumentError, 'missing block' unless block_given?
14
-
15
- old_stdout, old_stderr = STDOUT.dup, STDERR.dup
16
-
17
- IO.pipe do |stdout_read, stdout_write|
18
- IO.pipe do |stderr_read, stderr_write|
19
- STDOUT.reopen(stdout_write)
20
- STDERR.reopen(stderr_write)
21
-
22
- stdout_write.close
23
- stderr_write.close
24
-
25
- stdout_thread = Thread.new do
26
- while line = stdout_read.gets do
27
- stdout.print(line)
28
- end
29
- end
30
-
31
- stderr_thread = Thread.new do
32
- while line = stderr_read.gets do
33
- stderr.print(line)
34
- end
35
- end
36
-
37
- begin
38
- yield
39
- ensure
40
- # TODO: should the threads be killed here?
41
- STDOUT.reopen old_stdout
42
- STDERR.reopen old_stderr
43
- end
44
-
45
- stdout_thread.join
46
- stderr_thread.join
47
- end
48
- end
49
- end
50
11
  end
51
12
  end
52
13
  end
@@ -18,6 +18,13 @@ module RSpec
18
18
  def print(str = "")
19
19
  @string += str.to_s
20
20
  end
21
+
22
+ def flush
23
+ end
24
+
25
+ def closed?
26
+ @client.closed?
27
+ end
21
28
  end
22
29
  end
23
30
  end
@@ -0,0 +1,33 @@
1
+ module RSpec
2
+ module Interactive
3
+ class ThreadedOutput
4
+ attr_reader :string
5
+
6
+ def initialize(thread_map:, default:)
7
+ @thread_map = thread_map
8
+ @default = default
9
+ @string = ''
10
+ end
11
+
12
+ def write(name, str = "")
13
+ (@thread_map[Thread.current] || @default).write(name, str)
14
+ end
15
+
16
+ def puts(str = "")
17
+ (@thread_map[Thread.current] || @default).puts(str)
18
+ end
19
+
20
+ def print(str = "")
21
+ (@thread_map[Thread.current] || @default).puts(str)
22
+ end
23
+
24
+ def flush
25
+ (@thread_map[Thread.current] || @default).flush
26
+ end
27
+
28
+ def closed?
29
+ (@thread_map[Thread.current] || @default).closed?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Interactive
5
- VERSION = "0.9.6"
5
+ VERSION = "0.9.9"
6
6
  end
7
7
  end
@@ -19,6 +19,7 @@ require 'rspec-interactive/rubo_cop_command'
19
19
  require 'rspec-interactive/runner'
20
20
  require 'rspec-interactive/stdio'
21
21
  require 'rspec-interactive/string_output'
22
+ require 'rspec-interactive/threaded_output'
22
23
 
23
24
  module RSpec
24
25
  module Interactive
@@ -47,7 +48,7 @@ module RSpec
47
48
  @updated_files = []
48
49
  @stty_save = %x`stty -g`.chomp
49
50
  @file_change_mutex = Mutex.new
50
- @command_mutex = Mutex.new
51
+ @rspec_mutex = Mutex.new
51
52
  @output_stream = output_stream
52
53
  @input_stream = input_stream
53
54
  @error_stream = error_stream
@@ -61,29 +62,44 @@ module RSpec
61
62
  configure_pry
62
63
 
63
64
  @startup_thread = Thread.start do
64
- @startup_output = StringOutput.new
65
- Stdio.capture2(stdout: @startup_output, stderr: @startup_output) do
66
- @config_cache.record_configuration { @configuration.configure_rspec.call }
67
- start_file_watcher
68
- end
69
-
65
+ Thread.current.report_on_exception = false
70
66
  if server
71
67
  @server_thread = Thread.start do
72
68
  server = TCPServer.new port
73
69
 
74
- while client = server.accept
75
- request = client.gets
76
- args = Shellwords.split(request)
77
- rspec_for_server(client, args)
78
- client.close
70
+ while true
71
+ break unless client = server.accept
72
+ begin
73
+ request = client.gets
74
+ args = Shellwords.split(request)
75
+ rspec_for_server(client, args)
76
+ rescue StandardError => e
77
+ # It would be nice to log to the client here but it might be
78
+ # disconnected or disconnect before we successfully write. Any
79
+ # error here is unexpected so just log to the console.
80
+ @output_stream.puts
81
+ @output_stream.puts 'error handling client request'
82
+ log_exception(@output_stream, e)
83
+ ensure
84
+ client.close
85
+ end
79
86
  end
80
87
  end
81
88
  end
89
+
90
+ @startup_output = StringOutput.new
91
+ output = ThreadedOutput.new(thread_map: { Thread.current => @startup_output }, default: @output_stream)
92
+
93
+ Stdio.capture(stdout: output, stderr: output) do
94
+ @config_cache.record_configuration { @configuration.configure_rspec.call }
95
+ start_file_watcher
96
+ end
82
97
  end
83
98
 
84
99
  Pry.start
85
100
  @listener.stop if @listener
86
101
  @server_thread.exit if @server_thread
102
+ @startup_thread.exit if @startup_thread
87
103
  0
88
104
  end
89
105
 
@@ -141,17 +157,17 @@ module RSpec
141
157
  Pry.config.history_file = @history_file
142
158
  end
143
159
 
144
- def self.refresh
160
+ def self.refresh(output: @output_stream)
145
161
  @file_change_mutex.synchronize do
146
162
  @updated_files.uniq.each do |filename|
147
- @output_stream.puts "changed: #{filename}"
163
+ output.puts "changed: #{filename}"
148
164
  trace = TracePoint.new(:class) do |tp|
149
165
  @configuration.on_class_load.call(tp.self)
150
166
  end
151
167
  trace.enable
152
168
  load filename
153
169
  trace.disable
154
- @output_stream.puts
170
+ output.puts
155
171
  end
156
172
  @updated_files.clear
157
173
  end
@@ -180,50 +196,60 @@ module RSpec
180
196
  end
181
197
 
182
198
  def self.rspec(args)
183
- @runner = RSpec::Interactive::Runner.new(parse_args(args))
199
+ @rspec_mutex.synchronize do
200
+ begin
201
+ @runner = RSpec::Interactive::Runner.new(parse_args(args))
184
202
 
185
- refresh
203
+ refresh
186
204
 
187
- # Stop saving history in case a new Pry session is started for debugging.
188
- Pry.config.history_save = false
205
+ # Stop saving history in case a new Pry session is started for debugging.
206
+ Pry.config.history_save = false
189
207
 
190
- # RSpec::Interactive-specific RSpec configuration
191
- RSpec.configure do |config|
192
- config.error_stream = @error_stream
193
- config.output_stream = @output_stream
194
- config.start_time = RSpec::Core::Time.now
195
- end
208
+ # RSpec::Interactive-specific RSpec configuration
209
+ RSpec.configure do |config|
210
+ config.error_stream = @error_stream
211
+ config.output_stream = @output_stream
212
+ config.start_time = RSpec::Core::Time.now
213
+ end
196
214
 
197
- # Run.
198
- exit_code = @runner.run
199
- ensure
200
- @runner = nil
215
+ # Run.
216
+ @runner.run
217
+ ensure
218
+ @runner = nil
201
219
 
202
- # Reenable history
203
- Pry.config.history_save = true
220
+ # Reenable history
221
+ Pry.config.history_save = true
204
222
 
205
- # Reset
206
- RSpec.clear_examples
207
- RSpec.reset
208
- @config_cache.replay_configuration
223
+ # Reset
224
+ RSpec.clear_examples
225
+ RSpec.reset
226
+ @config_cache.replay_configuration
227
+ end
228
+ end
209
229
  end
210
230
 
211
231
  def self.rspec_for_server(client, args)
212
- @command_mutex.synchronize do
213
- # Prevent the debugger from being used. The server isn't interactive.
232
+ @rspec_mutex.synchronize do
214
233
  disable_pry = ENV['DISABLE_PRY']
215
- ENV['DISABLE_PRY'] = 'true'
216
-
217
234
  output = ClientOutput.new(client)
235
+
236
+ ENV['TEAMCITY_RAKE_RUNNER_DEBUG_OUTPUT_CAPTURER_ENABLED'] = 'false'
237
+ Rake::TeamCity::RunnerCommon.class_variable_set(:@@original_stdout, output)
238
+
239
+ return unless await_startup(output: output)
240
+
218
241
  Stdio.capture(stdout: output, stderr: output) do
219
- @runner = RSpec::Interactive::Runner.new(parse_args(args))
242
+ # Prevent the debugger from being used. The server isn't interactive.
243
+ ENV['DISABLE_PRY'] = 'true'
220
244
 
221
- refresh
245
+ runner = RSpec::Interactive::Runner.new(parse_args(args))
246
+
247
+ refresh(output: output)
222
248
 
223
249
  # RSpec::Interactive-specific RSpec configuration
224
250
  RSpec.configure do |config|
225
- config.error_stream = @error_stream
226
- config.output_stream = @output_stream
251
+ config.error_stream = output
252
+ config.output_stream = output
227
253
  config.start_time = RSpec::Core::Time.now
228
254
  end
229
255
 
@@ -239,15 +265,19 @@ module RSpec
239
265
  RSpec.configuration.formatter = Spec::Runner::Formatter::TeamcityFormatter
240
266
 
241
267
  # Run.
242
- exit_code = @runner.run
268
+ runner.run
269
+ rescue Errno::EPIPE, IOError
270
+ # Don't care.
271
+ ensure
272
+ ENV['DISABLE_PRY'] = disable_pry
273
+ runner = nil
243
274
 
244
275
  # Reset
245
276
  RSpec.clear_examples
246
277
  RSpec.reset
278
+
247
279
  @config_cache.replay_configuration
248
280
  end
249
- ensure
250
- ENV['DISABLE_PRY'] = disable_pry
251
281
  end
252
282
  end
253
283
 
@@ -259,28 +289,50 @@ module RSpec
259
289
  end
260
290
  end
261
291
 
262
- def self.eval(&block)
263
- if Thread.current.thread_variable_get('holding_lock')
292
+ def self.eval(line, options, &block)
293
+ return yield if line.nil? # EOF
294
+ return yield if line.empty? # blank line
295
+
296
+ if await_startup
264
297
  yield
265
298
  else
266
- @command_mutex.synchronize do
267
- Thread.current.thread_variable_set('holding_lock', true)
268
- if @startup_thread
269
- if @startup_thread.alive?
270
- @output_stream.puts 'waiting for configure_rspec...'
271
- end
272
- @startup_thread.join
273
- @startup_thread = nil
274
- unless @startup_output.string.empty?
275
- @output_stream.puts(@startup_output.string)
276
- end
277
- @startup_output = nil
278
- end
279
- yield
280
- ensure
281
- Thread.current.thread_variable_set('holding_lock', false)
282
- end
299
+ @output_stream.puts
300
+ true
301
+ end
302
+ end
303
+
304
+ def self.await_startup(output: @output_stream)
305
+ return true unless @startup_thread
306
+
307
+ if @startup_thread.alive?
308
+ output.puts 'waiting for configure_rspec...'
283
309
  end
310
+
311
+ begin
312
+ @startup_thread.join
313
+ @startup_thread = nil
314
+ print_startup_output(output: output)
315
+ true
316
+ rescue Interrupt
317
+ false
318
+ rescue StandardError => e
319
+ print_startup_output(output: output)
320
+ output.puts 'configure_rspec failed'
321
+ log_exception(output, e)
322
+ false
323
+ end
324
+ end
325
+
326
+ def self.log_exception(output, e)
327
+ output.puts "#{e.backtrace[0]}: #{e.message} (#{e.class})"
328
+ e.backtrace[1..-1].each { |b| output.puts "\t#{b}" }
329
+ end
330
+
331
+ def self.print_startup_output(output: @output_stream)
332
+ return if @startup_output.nil? || @startup_output.string.empty?
333
+
334
+ output.puts(@startup_output.string)
335
+ @startup_output = nil
284
336
  end
285
337
  end
286
338
  end
@@ -24,8 +24,12 @@ parser = OptionParser.new do |opts|
24
24
  end.parse
25
25
 
26
26
  server = TCPSocket.open(@options[:host], @options[:port])
27
- server.puts ARGV.map{ |arg| Shellwords.escape arg }.join(' ')
28
- while response = server.gets do
29
- puts response
27
+ begin
28
+ server.puts ARGV.map{ |arg| Shellwords.escape arg }.join(' ')
29
+ server.close_write
30
+ while response = server.gets do
31
+ puts response
32
+ end
33
+ ensure
34
+ server.close
30
35
  end
31
- server.close
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-interactive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.6
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-26 00:00:00.000000000 Z
11
+ date: 2022-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -103,6 +103,7 @@ files:
103
103
  - lib/rspec-interactive/runner.rb
104
104
  - lib/rspec-interactive/stdio.rb
105
105
  - lib/rspec-interactive/string_output.rb
106
+ - lib/rspec-interactive/threaded_output.rb
106
107
  - lib/rspec-interactive/version.rb
107
108
  - lib/teamcity/spec/runner/formatter/teamcity/formatter.rb
108
109
  - rspec-interactive.gemspec