rspec-interactive 0.9.7 → 0.9.10
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 +4 -4
- data/Gemfile.lock +1 -9
- data/lib/rspec-interactive/client_output.rb +7 -0
- data/lib/rspec-interactive/stdio.rb +1 -40
- data/lib/rspec-interactive/string_output.rb +7 -0
- data/lib/rspec-interactive/threaded_output.rb +33 -0
- data/lib/rspec-interactive/version.rb +1 -1
- data/lib/rspec-interactive.rb +140 -77
- data/rspec-interactive.gemspec +0 -1
- data/runner/rspec-interactive-run +8 -4
- metadata +3 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e00d8b9955bf056a3967733d54b89fdece90829b006b7d831de803670e33295
|
4
|
+
data.tar.gz: a5494e1160b97aa0b6c3e883e8457c5a6e6c2c54df1f26cd4d96c1ef15a4bbee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be9f403faf9fbfa42e38b0a07c70a4a338bc45cc6d9dc679e262653d3bc0a72d4ee1e15341b1693db3b51b0d2436da71b54525d22066fddd02d71a658c3ffb04
|
7
|
+
data.tar.gz: 0f9c77f7d09b008164bf802fa5507b46d6bb43de0d37e5b8aadc414751d919dc9347bf37262b65503e617259e9414a41d6c2e8fa082f77c8328790177b21fad0
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rspec-interactive (0.9.
|
5
|
-
listen
|
4
|
+
rspec-interactive (0.9.9)
|
6
5
|
pry
|
7
6
|
rspec-core
|
8
7
|
rspec-teamcity (= 1.0.0)
|
@@ -12,11 +11,7 @@ GEM
|
|
12
11
|
specs:
|
13
12
|
coderay (1.1.3)
|
14
13
|
diff-lcs (1.4.4)
|
15
|
-
ffi (1.15.5)
|
16
14
|
ffi (1.15.5-java)
|
17
|
-
listen (3.7.1)
|
18
|
-
rb-fsevent (~> 0.10, >= 0.10.3)
|
19
|
-
rb-inotify (~> 0.9, >= 0.9.10)
|
20
15
|
method_source (1.0.0)
|
21
16
|
pry (0.14.1)
|
22
17
|
coderay (~> 1.1)
|
@@ -25,9 +20,6 @@ GEM
|
|
25
20
|
coderay (~> 1.1)
|
26
21
|
method_source (~> 1.0)
|
27
22
|
spoon (~> 0.0)
|
28
|
-
rb-fsevent (0.11.1)
|
29
|
-
rb-inotify (0.10.1)
|
30
|
-
ffi (~> 1.0)
|
31
23
|
rspec (3.9.0)
|
32
24
|
rspec-core (~> 3.9.0)
|
33
25
|
rspec-expectations (~> 3.9.0)
|
@@ -1,52 +1,13 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Interactive
|
3
3
|
class Stdio
|
4
|
-
def self.
|
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
|
@@ -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
|
data/lib/rspec-interactive.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
+
require 'find'
|
1
2
|
require 'json'
|
2
|
-
require 'listen'
|
3
3
|
require 'pry'
|
4
4
|
require 'readline'
|
5
5
|
require 'rspec/core'
|
@@ -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
|
@@ -46,8 +47,7 @@ module RSpec
|
|
46
47
|
@history_file = history_file
|
47
48
|
@updated_files = []
|
48
49
|
@stty_save = %x`stty -g`.chomp
|
49
|
-
@
|
50
|
-
@command_mutex = Mutex.new
|
50
|
+
@rspec_mutex = Mutex.new
|
51
51
|
@output_stream = output_stream
|
52
52
|
@input_stream = input_stream
|
53
53
|
@error_stream = error_stream
|
@@ -59,28 +59,45 @@ module RSpec
|
|
59
59
|
check_rails
|
60
60
|
maybe_trap_interrupt
|
61
61
|
configure_pry
|
62
|
+
configure_watched_files
|
62
63
|
|
63
64
|
@startup_thread = Thread.start do
|
64
|
-
|
65
|
-
start_file_watcher
|
66
|
-
|
65
|
+
Thread.current.report_on_exception = false
|
67
66
|
if server
|
68
67
|
@server_thread = Thread.start do
|
69
68
|
server = TCPServer.new port
|
70
69
|
|
71
|
-
while
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
76
86
|
end
|
77
87
|
end
|
78
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
|
+
end
|
79
96
|
end
|
80
97
|
|
81
98
|
Pry.start
|
82
|
-
@listener.stop if @listener
|
83
99
|
@server_thread.exit if @server_thread
|
100
|
+
@startup_thread.exit if @startup_thread
|
84
101
|
0
|
85
102
|
end
|
86
103
|
|
@@ -113,18 +130,6 @@ module RSpec
|
|
113
130
|
end
|
114
131
|
end
|
115
132
|
|
116
|
-
def self.start_file_watcher
|
117
|
-
return if @configuration.watch_dirs.empty?
|
118
|
-
|
119
|
-
# Only polling seems to work in Docker.
|
120
|
-
@listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added|
|
121
|
-
@file_change_mutex.synchronize do
|
122
|
-
@updated_files.concat(added + modified)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
@listener.start
|
126
|
-
end
|
127
|
-
|
128
133
|
def self.configure_pry
|
129
134
|
# Set up IO.
|
130
135
|
Pry.config.input = Readline
|
@@ -138,19 +143,16 @@ module RSpec
|
|
138
143
|
Pry.config.history_file = @history_file
|
139
144
|
end
|
140
145
|
|
141
|
-
def self.refresh
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
@configuration.on_class_load.call(tp.self)
|
147
|
-
end
|
148
|
-
trace.enable
|
149
|
-
load filename
|
150
|
-
trace.disable
|
151
|
-
@output_stream.puts
|
146
|
+
def self.refresh(output: @output_stream)
|
147
|
+
get_updated_files.each do |filename|
|
148
|
+
output.puts "changed: #{filename}"
|
149
|
+
trace = TracePoint.new(:class) do |tp|
|
150
|
+
@configuration.on_class_load.call(tp.self)
|
152
151
|
end
|
153
|
-
|
152
|
+
trace.enable
|
153
|
+
load filename
|
154
|
+
trace.disable
|
155
|
+
output.puts
|
154
156
|
end
|
155
157
|
@configuration.refresh.call
|
156
158
|
end
|
@@ -177,51 +179,60 @@ module RSpec
|
|
177
179
|
end
|
178
180
|
|
179
181
|
def self.rspec(args)
|
180
|
-
@
|
182
|
+
@rspec_mutex.synchronize do
|
183
|
+
begin
|
184
|
+
@runner = RSpec::Interactive::Runner.new(parse_args(args))
|
181
185
|
|
182
|
-
|
186
|
+
refresh
|
183
187
|
|
184
|
-
|
185
|
-
|
188
|
+
# Stop saving history in case a new Pry session is started for debugging.
|
189
|
+
Pry.config.history_save = false
|
186
190
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
191
|
+
# RSpec::Interactive-specific RSpec configuration
|
192
|
+
RSpec.configure do |config|
|
193
|
+
config.error_stream = @error_stream
|
194
|
+
config.output_stream = @output_stream
|
195
|
+
config.start_time = RSpec::Core::Time.now
|
196
|
+
end
|
193
197
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
+
# Run.
|
199
|
+
@runner.run
|
200
|
+
ensure
|
201
|
+
@runner = nil
|
198
202
|
|
199
|
-
|
200
|
-
|
203
|
+
# Reenable history
|
204
|
+
Pry.config.history_save = true
|
201
205
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
+
# Reset
|
207
|
+
RSpec.clear_examples
|
208
|
+
RSpec.reset
|
209
|
+
@config_cache.replay_configuration
|
210
|
+
end
|
211
|
+
end
|
206
212
|
end
|
207
213
|
|
208
214
|
def self.rspec_for_server(client, args)
|
209
|
-
@
|
210
|
-
output = ClientOutput.new(client)
|
215
|
+
@rspec_mutex.synchronize do
|
211
216
|
disable_pry = ENV['DISABLE_PRY']
|
217
|
+
output = ClientOutput.new(client)
|
218
|
+
|
219
|
+
ENV['TEAMCITY_RAKE_RUNNER_DEBUG_OUTPUT_CAPTURER_ENABLED'] = 'false'
|
220
|
+
Rake::TeamCity::RunnerCommon.class_variable_set(:@@original_stdout, output)
|
221
|
+
|
222
|
+
return unless await_startup(output: output)
|
212
223
|
|
213
224
|
Stdio.capture(stdout: output, stderr: output) do
|
214
225
|
# Prevent the debugger from being used. The server isn't interactive.
|
215
226
|
ENV['DISABLE_PRY'] = 'true'
|
216
227
|
|
217
|
-
|
228
|
+
runner = RSpec::Interactive::Runner.new(parse_args(args))
|
218
229
|
|
219
|
-
refresh
|
230
|
+
refresh(output: output)
|
220
231
|
|
221
232
|
# RSpec::Interactive-specific RSpec configuration
|
222
233
|
RSpec.configure do |config|
|
223
|
-
config.error_stream =
|
224
|
-
config.output_stream =
|
234
|
+
config.error_stream = output
|
235
|
+
config.output_stream = output
|
225
236
|
config.start_time = RSpec::Core::Time.now
|
226
237
|
end
|
227
238
|
|
@@ -237,14 +248,17 @@ module RSpec
|
|
237
248
|
RSpec.configuration.formatter = Spec::Runner::Formatter::TeamcityFormatter
|
238
249
|
|
239
250
|
# Run.
|
240
|
-
|
251
|
+
runner.run
|
252
|
+
rescue Errno::EPIPE, IOError
|
253
|
+
# Don't care.
|
241
254
|
ensure
|
242
|
-
@runner = nil
|
243
255
|
ENV['DISABLE_PRY'] = disable_pry
|
256
|
+
runner = nil
|
244
257
|
|
245
258
|
# Reset
|
246
259
|
RSpec.clear_examples
|
247
260
|
RSpec.reset
|
261
|
+
|
248
262
|
@config_cache.replay_configuration
|
249
263
|
end
|
250
264
|
end
|
@@ -259,23 +273,72 @@ module RSpec
|
|
259
273
|
end
|
260
274
|
|
261
275
|
def self.eval(line, options, &block)
|
262
|
-
if line.nil?
|
276
|
+
return yield if line.nil? # EOF
|
277
|
+
return yield if line.empty? # blank line
|
278
|
+
|
279
|
+
if await_startup
|
263
280
|
yield
|
264
281
|
else
|
265
|
-
@
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
282
|
+
@output_stream.puts
|
283
|
+
true
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def self.await_startup(output: @output_stream)
|
288
|
+
return true unless @startup_thread
|
289
|
+
|
290
|
+
if @startup_thread.alive?
|
291
|
+
output.puts 'waiting for configure_rspec...'
|
292
|
+
end
|
293
|
+
|
294
|
+
begin
|
295
|
+
@startup_thread.join
|
296
|
+
@startup_thread = nil
|
297
|
+
print_startup_output(output: output)
|
298
|
+
true
|
299
|
+
rescue Interrupt
|
300
|
+
false
|
301
|
+
rescue StandardError => e
|
302
|
+
print_startup_output(output: output)
|
303
|
+
output.puts 'configure_rspec failed'
|
304
|
+
log_exception(output, e)
|
305
|
+
false
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def self.log_exception(output, e)
|
310
|
+
output.puts "#{e.backtrace[0]}: #{e.message} (#{e.class})"
|
311
|
+
e.backtrace[1..-1].each { |b| output.puts "\t#{b}" }
|
312
|
+
end
|
313
|
+
|
314
|
+
def self.print_startup_output(output: @output_stream)
|
315
|
+
return if @startup_output.nil? || @startup_output.string.empty?
|
316
|
+
|
317
|
+
output.puts(@startup_output.string)
|
318
|
+
@startup_output = nil
|
319
|
+
end
|
320
|
+
|
321
|
+
def self.configure_watched_files
|
322
|
+
@watched_files = get_watched_files
|
323
|
+
end
|
324
|
+
|
325
|
+
def self.get_watched_files
|
326
|
+
return Set.new if @configuration.watch_dirs.empty?
|
327
|
+
entries = Find.find(*@configuration.watch_dirs).flat_map do |file|
|
328
|
+
if FileTest.file?(file)
|
329
|
+
[[file, File.mtime(file).to_i]]
|
330
|
+
else
|
331
|
+
[]
|
277
332
|
end
|
278
333
|
end
|
334
|
+
entries.to_set
|
335
|
+
end
|
336
|
+
|
337
|
+
def self.get_updated_files
|
338
|
+
new_watched_files = get_watched_files
|
339
|
+
difference = new_watched_files - @watched_files
|
340
|
+
@watched_files = new_watched_files
|
341
|
+
difference.map(&:first)
|
279
342
|
end
|
280
343
|
end
|
281
344
|
end
|
data/rspec-interactive.gemspec
CHANGED
@@ -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
|
-
|
28
|
-
|
29
|
-
|
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.
|
4
|
+
version: 0.9.10
|
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-
|
11
|
+
date: 2022-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec-core
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.0.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: listen
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: pry
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -103,6 +89,7 @@ files:
|
|
103
89
|
- lib/rspec-interactive/runner.rb
|
104
90
|
- lib/rspec-interactive/stdio.rb
|
105
91
|
- lib/rspec-interactive/string_output.rb
|
92
|
+
- lib/rspec-interactive/threaded_output.rb
|
106
93
|
- lib/rspec-interactive/version.rb
|
107
94
|
- lib/teamcity/spec/runner/formatter/teamcity/formatter.rb
|
108
95
|
- rspec-interactive.gemspec
|