rspec-interactive 0.1.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +18 -7
- data/README.md +102 -0
- data/bin/console +1 -1
- data/bin/rspec-interactive +11 -2
- data/bin/test +2 -0
- data/examples/debugged_spec.rb +9 -0
- data/examples/failing_spec.rb +7 -0
- data/examples/other_passing_spec.rb +11 -0
- data/examples/passing_spec.rb +11 -0
- data/examples/spec_with_syntax_error.rb +5 -0
- data/lib/rspec-interactive.rb +101 -154
- data/lib/rspec-interactive/config.rb +23 -0
- data/lib/rspec-interactive/input_completer.rb +24 -0
- data/lib/rspec-interactive/rspec_command.rb +24 -0
- data/lib/rspec-interactive/rspec_config_cache.rb +96 -0
- data/lib/rspec-interactive/runner.rb +52 -29
- data/lib/rspec-interactive/version.rb +4 -2
- data/rspec-interactive.gemspec +5 -3
- data/run-with-local-dep.sh +36 -0
- data/tests/debugged_spec_test.rb +75 -0
- data/tests/eof_test.rb +10 -0
- data/tests/example_file_test.rb +54 -0
- data/tests/failing_spec_test.rb +41 -0
- data/tests/glob_test.rb +18 -0
- data/tests/line_number_test.rb +19 -0
- data/tests/passing_spec_test.rb +18 -0
- data/tests/rerun_failed_specs_test.rb +90 -0
- data/tests/spec_with_syntax_error_test.rb +30 -0
- data/tests/support/ansi.rb +32 -0
- data/tests/support/test_helper.rb +286 -0
- metadata +54 -5
- data/lib/repo.rb +0 -8
- data/rspec-console-0.1.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88fe45587c743f490177b20ef35c1a6372c56b22e631ca8d5bf24fb5836448bc
|
4
|
+
data.tar.gz: 23bd0531b2836fb9d3d6d86a462fe65b4f9ddde3b2671db608f1b76fbaf7989b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a066316a818ebaf46096e655d5e20c87280ae47863aeae564e275b066647b004afad528e40e0cc4dbe56935f6bd3c9275541302893b2fbd77c2eb01c84cdbf9c
|
7
|
+
data.tar.gz: 45d608d8bf7524a575bf833be24bcd13ec3ea6d2612da9ef40d7da5f9366fb43474eb078ab56c88f61c45d67143515a140d9d8de094e418906895cb277393386
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,29 +1,40 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rspec-
|
4
|
+
rspec-interactive (0.5.0)
|
5
5
|
listen
|
6
|
+
pry
|
7
|
+
rspec-core
|
6
8
|
|
7
9
|
GEM
|
8
10
|
remote: https://rubygems.org/
|
9
11
|
specs:
|
10
|
-
|
12
|
+
coderay (1.1.3)
|
13
|
+
diff-lcs (1.4.4)
|
14
|
+
ffi (1.15.3)
|
11
15
|
listen (3.5.1)
|
12
16
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
13
17
|
rb-inotify (~> 0.9, >= 0.9.10)
|
18
|
+
method_source (1.0.0)
|
19
|
+
pry (0.14.1)
|
20
|
+
coderay (~> 1.1)
|
21
|
+
method_source (~> 1.0)
|
14
22
|
rb-fsevent (0.11.0)
|
15
23
|
rb-inotify (0.10.1)
|
16
24
|
ffi (~> 1.0)
|
17
|
-
rspec-core (3.
|
18
|
-
rspec-support (~> 3.
|
19
|
-
rspec-
|
25
|
+
rspec-core (3.9.3)
|
26
|
+
rspec-support (~> 3.9.3)
|
27
|
+
rspec-expectations (3.9.4)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.9.0)
|
30
|
+
rspec-support (3.9.4)
|
20
31
|
|
21
32
|
PLATFORMS
|
22
33
|
x86_64-darwin-20
|
23
34
|
|
24
35
|
DEPENDENCIES
|
25
|
-
rspec-
|
26
|
-
rspec-
|
36
|
+
rspec-expectations
|
37
|
+
rspec-interactive!
|
27
38
|
|
28
39
|
BUNDLED WITH
|
29
40
|
2.2.17
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# RSpec Interactive
|
2
|
+
|
3
|
+
An Pry console capable of running specs.
|
4
|
+
|
5
|
+
## Installation & Configuration
|
6
|
+
|
7
|
+
Install:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'rspec-interactive'
|
11
|
+
```
|
12
|
+
|
13
|
+
Add a config file which configures RSpec and RSpec::Interactive, for example `spec/rspec_interactive.rb`:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
load 'spec/spec_helper.rb'
|
17
|
+
|
18
|
+
RSpec::Interactive.configure do |config|
|
19
|
+
# Directories to watch for file changes. When a file changes, it will be reloaded like `load 'path/to/file'`.
|
20
|
+
config.watch_dirs += ["app", "lib", "config"]
|
21
|
+
|
22
|
+
# This block is invoked on startup. RSpec configuration must happen here so that it can be reloaded before each test run.
|
23
|
+
config.configure_rspec do
|
24
|
+
require './spec/spec_helper.rb'
|
25
|
+
end
|
26
|
+
|
27
|
+
# Invoked whenever a class is loaded due to a file change in one of the watch_dirs.
|
28
|
+
config.on_class_load do |clazz|
|
29
|
+
clazz.clear_validators! if clazz < ApplicationRecord
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
Update `.gitignore`
|
35
|
+
|
36
|
+
```shell
|
37
|
+
echo '.rspec_interactive_history' >> .gitignore
|
38
|
+
```
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
See more examples below.
|
43
|
+
|
44
|
+
```shell
|
45
|
+
bundle exec rspec-interactive spec/rspec_interactive.rb
|
46
|
+
```
|
47
|
+
|
48
|
+
## Example Usage In This Repo
|
49
|
+
|
50
|
+
Start:
|
51
|
+
|
52
|
+
```shell
|
53
|
+
bundle exec rspec-interactive
|
54
|
+
```
|
55
|
+
|
56
|
+
Run a passing spec:
|
57
|
+
|
58
|
+
```shell
|
59
|
+
[1] pry(main)> rspec examples/passing_spec.rb
|
60
|
+
```
|
61
|
+
|
62
|
+
Run a failing spec:
|
63
|
+
|
64
|
+
```shell
|
65
|
+
[3] pry(main)> rspec examples/failing_spec.rb
|
66
|
+
```
|
67
|
+
|
68
|
+
Run an example group:
|
69
|
+
|
70
|
+
```shell
|
71
|
+
[5] pry(main)> rspec examples/passing_spec.rb:4
|
72
|
+
```
|
73
|
+
|
74
|
+
Run multiple specs:
|
75
|
+
|
76
|
+
```shell
|
77
|
+
[6] pry(main)> rspec examples/passing_spec.rb examples/failing_spec.rb
|
78
|
+
```
|
79
|
+
|
80
|
+
Debug a spec (use `exit` to resume while debugging):
|
81
|
+
|
82
|
+
```shell
|
83
|
+
[7] pry(main)> rspec examples/debugged_spec.rb
|
84
|
+
```
|
85
|
+
|
86
|
+
Run multiple specs using globbing (use `exit` to resume while debugging):
|
87
|
+
|
88
|
+
```shell
|
89
|
+
[8] pry(main)> rspec examples/*_spec.rb
|
90
|
+
```
|
91
|
+
|
92
|
+
Exit:
|
93
|
+
|
94
|
+
```shell
|
95
|
+
[9] pry(main)> exit
|
96
|
+
```
|
97
|
+
|
98
|
+
## Running Tests
|
99
|
+
|
100
|
+
```shell
|
101
|
+
bundle exec bin/test
|
102
|
+
```
|
data/bin/console
CHANGED
data/bin/rspec-interactive
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'rspec-interactive
|
3
|
+
require 'rspec-interactive'
|
4
4
|
|
5
|
-
|
5
|
+
if ARGV.size == 0
|
6
|
+
RSpec::Interactive.start
|
7
|
+
elsif ARGV.size == 1
|
8
|
+
RSpec::Interactive.start(config_file: ARGV[0])
|
9
|
+
else
|
10
|
+
STDERR.puts "expected 0 or 1 argument, got: #{args.join(', ')}"
|
11
|
+
STDERR.puts ''
|
12
|
+
STDOUT.puts 'usage: rspec-interactive [config-file]'
|
13
|
+
exit 1
|
14
|
+
end
|
data/bin/test
ADDED
data/lib/rspec-interactive.rb
CHANGED
@@ -1,205 +1,152 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
1
|
require 'json'
|
4
2
|
require 'listen'
|
3
|
+
require 'pry'
|
5
4
|
require 'readline'
|
6
5
|
require 'rspec/core'
|
7
|
-
require 'shellwords'
|
8
|
-
|
9
|
-
require_relative 'rspec-interactive/runner.rb'
|
10
6
|
|
11
|
-
|
12
|
-
|
7
|
+
require 'rspec-interactive/runner'
|
8
|
+
require 'rspec-interactive/config'
|
9
|
+
require 'rspec-interactive/rspec_config_cache'
|
10
|
+
require 'rspec-interactive/input_completer'
|
11
|
+
require 'rspec-interactive/rspec_command'
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
MAX_HISTORY_ITEMS = 100
|
17
|
-
COMMANDS = ['help', 'rspec']
|
13
|
+
module RSpec
|
14
|
+
module Interactive
|
18
15
|
|
19
|
-
|
20
|
-
if args.size > 1
|
21
|
-
STDERR.puts "expected 0 or 1 argument, got: #{args.join(', ')}"
|
22
|
-
exit!(1)
|
23
|
-
end
|
16
|
+
DEFAULT_HISTORY_FILE = '.rspec_interactive_history'.freeze
|
24
17
|
|
25
|
-
|
26
|
-
|
27
|
-
@runner = nil
|
28
|
-
load_config(args[0])
|
18
|
+
class << self
|
19
|
+
attr_accessor :configuration
|
29
20
|
end
|
30
21
|
|
31
|
-
def
|
32
|
-
|
33
|
-
load_history
|
34
|
-
configure_auto_complete
|
35
|
-
trap_interrupt
|
36
|
-
start_console
|
22
|
+
def self.configure(&block)
|
23
|
+
block.call(@configuration)
|
37
24
|
end
|
38
25
|
|
39
|
-
|
26
|
+
def self.start(config_file: nil, history_file: DEFAULT_HISTORY_FILE, input_stream: STDIN, output_stream: STDOUT, error_stream: STDERR)
|
27
|
+
@history_file = history_file
|
28
|
+
@updated_files = []
|
29
|
+
@stty_save = %x`stty -g`.chomp
|
30
|
+
@mutex = Mutex.new
|
31
|
+
@output_stream = output_stream
|
32
|
+
@input_stream = input_stream
|
33
|
+
@error_stream = error_stream
|
34
|
+
@config_cache = RSpec::Interactive::ConfigCache.new
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
load @config["init_script"]
|
44
|
-
end
|
36
|
+
@configuration = Configuration.new
|
37
|
+
load config_file if config_file
|
45
38
|
|
46
|
-
|
47
|
-
if !File.exists? CONFIG_FILE
|
48
|
-
STDERR.puts "file not found: #{CONFIG_FILE}"
|
49
|
-
exit!(1)
|
50
|
-
end
|
39
|
+
@config_cache.record_configuration { @configuration.configure_rspec.call }
|
51
40
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
41
|
+
check_rails
|
42
|
+
start_file_watcher
|
43
|
+
trap_interrupt
|
44
|
+
configure_pry
|
57
45
|
|
58
|
-
|
59
|
-
if
|
60
|
-
|
61
|
-
|
62
|
-
STDERR.puts "invalid config: #{name}"
|
63
|
-
exit!(1)
|
64
|
-
end
|
46
|
+
Pry.start
|
47
|
+
@listener.stop if @listener
|
48
|
+
0
|
49
|
+
end
|
65
50
|
|
66
|
-
|
67
|
-
if
|
68
|
-
|
51
|
+
def self.check_rails
|
52
|
+
if defined?(::Rails)
|
53
|
+
if ::Rails.application.config.cache_classes
|
54
|
+
@error_stream.puts "warning: Rails.application.config.cache_classes enabled. Disable to ensure code is reloaded."
|
55
|
+
end
|
69
56
|
end
|
57
|
+
end
|
70
58
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
print "Multiple simultaneous configs not yet supported. Please choose a config. #{names.join(', ')}: "
|
76
|
-
answer = STDIN.gets.chomp
|
77
|
-
if answer.strip.empty?
|
78
|
-
return configs[0]
|
79
|
-
end
|
80
|
-
config = configs.find { |e| e["name"] == answer }
|
81
|
-
return config if config
|
82
|
-
STDERR.puts "invalid config: #{answer}"
|
59
|
+
def self.configure_rspec
|
60
|
+
RSpec.configure do |config|
|
61
|
+
config.error_stream = @error_stream
|
62
|
+
config.output_stream = @output_stream
|
83
63
|
end
|
84
64
|
end
|
85
65
|
|
86
|
-
def trap_interrupt
|
66
|
+
def self.trap_interrupt
|
87
67
|
trap('INT') do
|
88
|
-
@
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
68
|
+
if @runner
|
69
|
+
# We are on a different thread. There is a race here. Ignore nil.
|
70
|
+
@runner&.quit
|
71
|
+
else
|
72
|
+
@output_stream.puts
|
73
|
+
system "stty", @stty_save
|
74
|
+
exit!(0)
|
96
75
|
end
|
97
76
|
end
|
98
77
|
end
|
99
78
|
|
100
|
-
def start_file_watcher
|
101
|
-
|
102
|
-
listener = Listen.to(*@config["watch_dirs"], only: /\.rb$/, force_polling: true) do |modified, added, removed|
|
103
|
-
(added + modified).each { |filename| load filename }
|
104
|
-
end
|
105
|
-
end
|
79
|
+
def self.start_file_watcher
|
80
|
+
return if @configuration.watch_dirs.empty?
|
106
81
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
Readline::HISTORY << line.strip
|
82
|
+
# Only polling seems to work in Docker.
|
83
|
+
@listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added, removed|
|
84
|
+
@mutex.synchronize do
|
85
|
+
@updated_files.concat(added + modified)
|
112
86
|
end
|
113
87
|
end
|
88
|
+
@listener.start
|
114
89
|
end
|
115
90
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
91
|
+
def self.configure_pry
|
92
|
+
# Prevent Pry from trapping too. It will break ctrl-c handling.
|
93
|
+
Pry.config.should_trap_interrupts = false
|
119
94
|
|
120
|
-
|
121
|
-
|
122
|
-
|
95
|
+
# Set up IO.
|
96
|
+
Pry.config.input = Readline
|
97
|
+
Pry.config.output = @output_stream
|
98
|
+
Readline.output = @output_stream
|
99
|
+
Readline.input = @input_stream
|
123
100
|
|
124
|
-
|
125
|
-
|
126
|
-
puts
|
127
|
-
system "stty", @stty_save
|
128
|
-
exit!(0)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Ignore blank lines.
|
132
|
-
if buffer.empty?
|
133
|
-
Readline::HISTORY.pop
|
134
|
-
next
|
135
|
-
end
|
101
|
+
# Use custom completer to get file completion.
|
102
|
+
Pry.config.completer = RSpec::Interactive::InputCompleter
|
136
103
|
|
137
|
-
|
138
|
-
|
139
|
-
file = File.open(HISTORY_FILE, 'w')
|
140
|
-
lines = Readline::HISTORY.to_a
|
141
|
-
lines[-[MAX_HISTORY_ITEMS, lines.size].min..-1].each do |line|
|
142
|
-
file.write(line.strip + "\n")
|
143
|
-
end
|
144
|
-
file.close
|
145
|
-
end
|
146
|
-
|
147
|
-
# Handle quoting, etc.
|
148
|
-
args = Shellwords.shellsplit(buffer)
|
149
|
-
next if args.empty?
|
104
|
+
Pry.config.history_file = @history_file
|
105
|
+
end
|
150
106
|
|
151
|
-
|
152
|
-
|
153
|
-
|
107
|
+
def self.rspec(args)
|
108
|
+
parsed_args = args.flat_map do |arg|
|
109
|
+
if arg.match(/[\*\?\[]/)
|
110
|
+
glob = Dir.glob(arg)
|
111
|
+
glob.empty? ? [arg] : glob
|
154
112
|
else
|
155
|
-
|
113
|
+
[arg]
|
156
114
|
end
|
157
115
|
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def help(args)
|
161
|
-
if !args.empty?
|
162
|
-
STDERR.puts "invalid argument(s): #{args}"
|
163
|
-
return
|
164
|
-
end
|
165
|
-
|
166
|
-
print "commands:\n\n"
|
167
|
-
print "help - print this message\n"
|
168
|
-
print "rspec - execute the specified spec file(s), wildcards allowed\n"
|
169
|
-
end
|
170
116
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
117
|
+
@mutex.synchronize do
|
118
|
+
@updated_files.uniq.each do |filename|
|
119
|
+
@output_stream.puts "modified: #{filename}"
|
120
|
+
trace = TracePoint.new(:class) do |tp|
|
121
|
+
@configuration.on_class_load.call(tp.self)
|
122
|
+
end
|
123
|
+
trace.enable
|
124
|
+
load filename
|
125
|
+
trace.disable
|
126
|
+
@output_stream.puts
|
127
|
+
end
|
128
|
+
@updated_files.clear
|
175
129
|
end
|
176
130
|
|
177
|
-
|
178
|
-
filenames = args.flat_map { |filename| Dir.glob(filename) }
|
131
|
+
@runner = RSpec::Interactive::Runner.new(parsed_args)
|
179
132
|
|
180
|
-
#
|
181
|
-
|
133
|
+
# Stop saving history in case a new Pry session is started for debugging.
|
134
|
+
Pry.config.history_save = false
|
182
135
|
|
183
|
-
#
|
184
|
-
|
185
|
-
# handler sets it to true.
|
186
|
-
@mutex.synchronize { @runner = RSpecInteractive::Runner.new(filenames) }
|
136
|
+
# RSpec::Interactive-specific RSpec configuration
|
137
|
+
configure_rspec
|
187
138
|
|
188
|
-
# Run
|
189
|
-
@runner.run
|
139
|
+
# Run.
|
140
|
+
exit_code = @runner.run
|
141
|
+
@runner = nil
|
190
142
|
|
191
|
-
#
|
192
|
-
|
143
|
+
# Reenable history
|
144
|
+
Pry.config.history_save = true
|
193
145
|
|
194
|
-
#
|
146
|
+
# Reset
|
195
147
|
RSpec.clear_examples
|
196
|
-
|
197
|
-
|
198
|
-
# also modifies the list of formatters. Reset them to whatever the init script set.
|
199
|
-
if !RSpec.configuration.formatters.empty?
|
200
|
-
raise "internal error. expected formatters to be cleared."
|
201
|
-
end
|
202
|
-
formatters.each { |f| RSpec.configuration.add_formatter(f) }
|
148
|
+
RSpec.reset
|
149
|
+
@config_cache.replay_configuration
|
203
150
|
end
|
204
151
|
end
|
205
152
|
end
|