rspec-interactive 0.6.1 → 0.8.1

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: 858197f05a88cbac9b4acf36c6220a79c15bc008945fa87cef7c008e20ca172d
4
- data.tar.gz: b9a34852edc5bc544e9117ebfef1c6190e7ecae73cb7a29e2929f82743e72ed5
3
+ metadata.gz: 255c2aca56cb003fad2c6e7e5f72cb75b2ed82f1820edb42294ded182dbdd25c
4
+ data.tar.gz: afb9f469028aa3a4388585e6d34e281ce1bae8fe7227e73ba0939f2cf3585255
5
5
  SHA512:
6
- metadata.gz: ec6835e7baeb24d4126edb542629529e308ab9ecd79a28697c03f8290a8c6b5d15bbe6fd645338e870df124a073638c45bab0f790f8bb09becfd4a613d995cc0
7
- data.tar.gz: cbf961a6c0a60cfc3cced32778f34ebbf7ae3e97399c017148cbe88e1229f5d96b2ab6f374ad4bc68e6eaaf9e7f18013e5510cab76521f4d70c0e90cb485b126
6
+ metadata.gz: abae1515ca7dade3476088e21fef619f1cdda2b3b126f0a19db30b0aabd2f7250bee9874f11cccf5a836d39dd45d7b6a5848003a32637bf2eb925c4d229622dc
7
+ data.tar.gz: 90c4118df931f6e30c3af286f8fb9a1a382bd30dfcd3d052480943fa4f305975784c87e51fddba17de4343ef0748169c07831dc52e7f31190efefef516216efa
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ ruby '3.0.0'
4
+
3
5
  source "https://rubygems.org"
4
6
 
5
7
  gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-interactive (0.6.0)
4
+ rspec-interactive (0.8.0)
5
5
  listen
6
6
  pry
7
7
  rspec-core
@@ -36,5 +36,8 @@ DEPENDENCIES
36
36
  rspec-expectations
37
37
  rspec-interactive!
38
38
 
39
+ RUBY VERSION
40
+ ruby 3.0.0p0
41
+
39
42
  BUNDLED WITH
40
43
  2.2.17
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RSpec Interactive
2
2
 
3
- An Pry console capable of running specs.
3
+ A Pry console capable of running specs.
4
4
 
5
5
  ## Installation & Configuration
6
6
 
@@ -17,7 +17,7 @@ RSpec::Interactive.configure do |config|
17
17
  # Directories to watch for file changes. When a file changes, it will be reloaded like `load 'path/to/file'`.
18
18
  config.watch_dirs += ["app", "lib", "config"]
19
19
 
20
- # This block is invoked on startup. RSpec configuration must happen here so that it can be reloaded before each test run.
20
+ # This block is invoked on startup. RSpec configuration must happen here so that it can be cached and reloaded before each test run.
21
21
  config.configure_rspec do
22
22
  require './spec/spec_helper.rb'
23
23
  end
@@ -26,6 +26,13 @@ RSpec::Interactive.configure do |config|
26
26
  config.on_class_load do |clazz|
27
27
  clazz.clear_validators! if clazz < ApplicationRecord
28
28
  end
29
+
30
+ # Invoked before each invocation of RSpec. Can also be manually invoked by typing `refresh` in the console.
31
+ # Any modified/added files will be loaded via `load` before invoking.
32
+ config.refresh do
33
+ FactoryBot.reload
34
+ Rails.application.reloader.reload!
35
+ end
29
36
  end
30
37
  ```
31
38
 
@@ -35,6 +42,31 @@ Update `.gitignore`
35
42
  echo '.rspec_interactive_history' >> .gitignore
36
43
  ```
37
44
 
45
+ ### A Note About FactoryBot
46
+
47
+ It is not possible to reload a file containing FactoryBot factory definitions via `load` because FactoryBot does not allow factories to be redefined. Be carefule not to add any directories to `watch_dirs` which contain factory definitions. Instead, you should configure the location of your factories like the following in your `spec_helper.rb`:
48
+
49
+ ```ruby
50
+ FactoryBot.definition_file_paths = %w(spec/factories)
51
+ FactoryBot.find_definitions # Only if not using Rails
52
+ ```
53
+
54
+ Then add the following to your RSpec Interactive config
55
+
56
+ ```ruby
57
+ RSpec::Interactive.configure do |config|
58
+ config.refresh do
59
+ FactoryBot.reload
60
+ end
61
+ end
62
+ ```
63
+
64
+ This will cause factories to be reloaded before each test run and also whenever the `refresh` command is invoked in the console.
65
+
66
+ See: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#configure-your-test-suite
67
+
68
+ See: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#rails-preloaders-and-rspec
69
+
38
70
  ## Usage
39
71
 
40
72
  Optionally, specify a config file with `--config <config-file>`. Optionally, specify arguments to an initial RSpec invocation with `--initial-rspec-args <initial-rspec-args>`.
@@ -80,7 +112,6 @@ Run multiple specs:
80
112
  ```shell
81
113
  [6] pry(main)> rspec examples/passing_spec.rb examples/failing_spec.rb
82
114
  ```
83
-
84
115
  Debug a spec (use `exit` to resume while debugging):
85
116
 
86
117
  ```shell
@@ -9,7 +9,9 @@ require 'rspec-interactive/runner'
9
9
  require 'rspec-interactive/config'
10
10
  require 'rspec-interactive/rspec_config_cache'
11
11
  require 'rspec-interactive/input_completer'
12
+ require 'rspec-interactive/refresh_command'
12
13
  require 'rspec-interactive/rspec_command'
14
+ require 'rspec-interactive/rubo_cop_command'
13
15
 
14
16
  module RSpec
15
17
  module Interactive
@@ -37,13 +39,15 @@ module RSpec
37
39
  @configuration = Configuration.new
38
40
  load config_file if config_file
39
41
 
40
- @config_cache.record_configuration { @configuration.configure_rspec.call }
41
-
42
42
  check_rails
43
- start_file_watcher
44
43
  trap_interrupt
45
44
  configure_pry
46
45
 
46
+ @init_thread = Thread.start {
47
+ @config_cache.record_configuration { @configuration.configure_rspec.call }
48
+ start_file_watcher
49
+ }
50
+
47
51
  if initial_rspec_args
48
52
  open(@history_file, 'a') { |f| f.puts "rspec #{initial_rspec_args.strip}" }
49
53
  rspec Shellwords.split(initial_rspec_args)
@@ -86,7 +90,7 @@ module RSpec
86
90
  return if @configuration.watch_dirs.empty?
87
91
 
88
92
  # Only polling seems to work in Docker.
89
- @listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added, removed|
93
+ @listener = Listen.to(*@configuration.watch_dirs, only: /\.rb$/, force_polling: true) do |modified, added|
90
94
  @mutex.synchronize do
91
95
  @updated_files.concat(added + modified)
92
96
  end
@@ -110,19 +114,10 @@ module RSpec
110
114
  Pry.config.history_file = @history_file
111
115
  end
112
116
 
113
- def self.rspec(args)
114
- parsed_args = args.flat_map do |arg|
115
- if arg.match(/[\*\?\[]/)
116
- glob = Dir.glob(arg)
117
- glob.empty? ? [arg] : glob
118
- else
119
- [arg]
120
- end
121
- end
122
-
117
+ def self.refresh
123
118
  @mutex.synchronize do
124
119
  @updated_files.uniq.each do |filename|
125
- @output_stream.puts "modified: #{filename}"
120
+ @output_stream.puts "changed: #{filename}"
126
121
  trace = TracePoint.new(:class) do |tp|
127
122
  @configuration.on_class_load.call(tp.self)
128
123
  end
@@ -133,9 +128,30 @@ module RSpec
133
128
  end
134
129
  @updated_files.clear
135
130
  end
131
+ @configuration.refresh.call
132
+ end
133
+
134
+ def self.rspec(args)
135
+ parsed_args = args.flat_map do |arg|
136
+ if arg.match(/[\*\?\[]/)
137
+ glob = Dir.glob(arg)
138
+ glob.empty? ? [arg] : glob
139
+ else
140
+ [arg]
141
+ end
142
+ end
136
143
 
144
+ # Initialize the runner before waiting for the init thread so that the interrupt
145
+ # handler will cancel the RSpec invocation rather than kill the app.
137
146
  @runner = RSpec::Interactive::Runner.new(parsed_args)
138
147
 
148
+ if @init_thread&.alive?
149
+ @init_thread.join
150
+ @init_thread = nil
151
+ end
152
+
153
+ refresh
154
+
139
155
  # Stop saving history in case a new Pry session is started for debugging.
140
156
  Pry.config.history_save = false
141
157
 
@@ -153,6 +169,21 @@ module RSpec
153
169
  RSpec.clear_examples
154
170
  RSpec.reset
155
171
  @config_cache.replay_configuration
172
+ ensure
173
+ @runner = nil
174
+ end
175
+
176
+ def self.rubo_cop(args)
177
+ if @init_thread&.alive?
178
+ @init_thread.join
179
+ @init_thread = nil
180
+ end
181
+
182
+ if defined?(RuboCop)
183
+ RuboCop::CLI.new.run args
184
+ else
185
+ @error_stream.puts "fatal: RuboCop not found. Is the gem installed in this project?"
186
+ end
156
187
  end
157
188
  end
158
189
  end
@@ -1,12 +1,13 @@
1
1
  module RSpec
2
2
  module Interactive
3
3
  class Configuration
4
- attr_accessor :watch_dirs, :configure_rspec, :on_class_load
4
+ attr_accessor :watch_dirs, :configure_rspec, :on_class_load, :refresh
5
5
 
6
6
  def initialize
7
7
  @watch_dirs = []
8
8
  @configure_rspec = proc {}
9
9
  @on_class_load = proc {}
10
+ @refresh = proc {}
10
11
  end
11
12
 
12
13
  def configure_rspec(&block)
@@ -18,6 +19,11 @@ module RSpec
18
19
  return @on_class_load unless block
19
20
  @on_class_load = block
20
21
  end
22
+
23
+ def refresh(&block)
24
+ return @refresh unless block
25
+ @refresh = block
26
+ end
21
27
  end
22
28
  end
23
29
  end
@@ -1,23 +1,27 @@
1
1
  module RSpec::Interactive
2
2
  class InputCompleter < Pry::InputCompleter
3
3
 
4
- def rspec_completions(string)
4
+ def cli_completions(command, string)
5
5
  line = Readline.line_buffer
6
6
  before_current = Readline.point == string.length ? '' : line[0..(Readline.point - string.length)]
7
7
  before_cursor = line[0..(Readline.point - 1)]
8
8
 
9
- if line.match(/^ *rspec +/)
9
+ if line.match(/^ *#{command} +/)
10
10
  Dir[string + '*'].map { |filename| File.directory?(filename) ? "#{filename}/" : filename }
11
- elsif before_current.strip.empty? && "rspec".match(/^#{Regexp.escape(string)}/)
12
- ["rspec "]
11
+ elsif before_current.strip.empty? && command.match(/^#{Regexp.escape(string)}/)
12
+ ["#{command} "]
13
13
  else
14
14
  nil
15
15
  end
16
16
  end
17
17
 
18
18
  def call(str, options = {})
19
- rspec_completions = rspec_completions(str)
19
+ rspec_completions = cli_completions('rspec', str)
20
20
  return rspec_completions if rspec_completions
21
+
22
+ rubocop_completions = cli_completions('rubocop', str)
23
+ return rubocop_completions if rubocop_completions
24
+
21
25
  super
22
26
  end
23
27
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec::Interactive
4
+ class RefreshCommand < Pry::ClassCommand
5
+ match 'refresh'
6
+ description "Load any files in watched directories which have changed since the last refresh or rspec invocation."
7
+
8
+ banner <<-BANNER
9
+ Usage: refresh
10
+ BANNER
11
+
12
+ command_options(
13
+ :keep_retval => false
14
+ )
15
+
16
+ def process
17
+ RSpec::Interactive.refresh
18
+ end
19
+
20
+ Pry::Commands.add_command(::RSpec::Interactive::RefreshCommand)
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec::Interactive
4
+ class RuboCopCommand < Pry::ClassCommand
5
+ match 'rubocop'
6
+ description "Invoke RuboCop."
7
+
8
+ banner <<-BANNER
9
+ Usage: rubocop [arguments]
10
+
11
+ See https://docs.rubocop.org/rubocop/usage/basic_usage.html
12
+ BANNER
13
+
14
+ command_options(
15
+ :keep_retval => false
16
+ )
17
+
18
+ def process
19
+ RSpec::Interactive.rubo_cop(args)
20
+ end
21
+
22
+ Pry::Commands.add_command(::RSpec::Interactive::RuboCopCommand)
23
+ end
24
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Interactive
5
- VERSION = "0.6.1"
5
+ VERSION = "0.8.1"
6
6
  end
7
7
  end
data/scripts/release.sh CHANGED
@@ -15,6 +15,8 @@ fi
15
15
  NEW_VERSION=$1
16
16
  CURRENT_VERSION=$(grep VERSION lib/rspec-interactive/version.rb | cut -d'"' -f 2)
17
17
 
18
+ bundle exec bin/test
19
+
18
20
  echo "Updating from v$CURRENT_VERSION to v$NEW_VERSION. Press enter to continue."
19
21
  read
20
22
 
@@ -23,3 +25,4 @@ gem build
23
25
  gem push rspec-interactive-$NEW_VERSION.gem
24
26
  bundle install
25
27
  git commit -a -m "v$NEW_VERSION Release"
28
+ open "https://github.com/nicholasdower/rspec-interactive/releases/new?title=v$NEW_VERSION%20Release&tag=v$NEW_VERSION&target=$(git rev-parse HEAD)"
@@ -7,7 +7,11 @@ examples = Tempfile.new('examples')
7
7
 
8
8
  config = Tempfile.new('config')
9
9
  config.write <<~EOF
10
- RSpec.configuration.example_status_persistence_file_path = "#{examples.path}"
10
+ RSpec::Interactive.configure do |config|
11
+ config.configure_rspec do
12
+ RSpec.configuration.example_status_persistence_file_path = "#{examples.path}"
13
+ end
14
+ end
11
15
  EOF
12
16
  config.rewind
13
17
 
@@ -4,11 +4,15 @@ examples = Tempfile.new('examples')
4
4
 
5
5
  config = Tempfile.new('config')
6
6
  config.write <<~EOF
7
- RSpec.configuration.example_status_persistence_file_path = "#{examples.path}"
7
+ RSpec::Interactive.configure do |config|
8
+ config.configure_rspec do
9
+ RSpec.configuration.example_status_persistence_file_path = "#{examples.path}"
10
+ end
11
+ end
8
12
  EOF
9
13
  config.rewind
10
14
 
11
- Test.test "failing spec with example file", config_path: config.path do
15
+ Test.test "rerun failing spec with example file", config_path: config.path do
12
16
  await_prompt
13
17
 
14
18
  RSpec.configuration.backtrace_exclusion_patterns = [ /.*/ ]
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.6.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-20 00:00:00.000000000 Z
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec-core
@@ -78,8 +78,10 @@ files:
78
78
  - lib/rspec-interactive.rb
79
79
  - lib/rspec-interactive/config.rb
80
80
  - lib/rspec-interactive/input_completer.rb
81
+ - lib/rspec-interactive/refresh_command.rb
81
82
  - lib/rspec-interactive/rspec_command.rb
82
83
  - lib/rspec-interactive/rspec_config_cache.rb
84
+ - lib/rspec-interactive/rubo_cop_command.rb
83
85
  - lib/rspec-interactive/runner.rb
84
86
  - lib/rspec-interactive/version.rb
85
87
  - rspec-interactive.gemspec