rspec-interactive 0.6.1 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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