rubocop-rspec 1.28.0 → 1.29.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6138f067fde5bf88b21e56895a967a55e8bc9357dfd16d0044fd2777c5cbadc7
4
- data.tar.gz: 64d630cc6a9f3d1413a8155486f002a1d524f9750ebf2c18d5c5bc485c21e438
3
+ metadata.gz: 443658797afd25742895f47e865522055e00c498fb74ca74fda1d09468d86470
4
+ data.tar.gz: 71e9ab9356e4287df026b2d051bc2de4407517021c62c28cc66dfb5164dda753
5
5
  SHA512:
6
- metadata.gz: 57246fef93f5061741c542a5710c16c905ff086da1d06974473e8b6ad54a6c84e26c4d79f7f538a92bca7d53ceb4c20e9eace2d65536922168e4ca227bb5a152
7
- data.tar.gz: 6940142c7e889246bab48ccd06dc35784731181b774fc047ba9359f5e5b5975b5b10cee3a2ac970e11142ed1ae9dfc004e88e30cba5470945088a23cd7506b8d
6
+ metadata.gz: 714551b4c0b85485ed5a0b0bdfc67cbca73b16fbb2a1ca5b498f578f928a04fe2ab58d1d9916bd140c64a62e23d81e9ea66944c294a98486776df9f204a2ba8f
7
+ data.tar.gz: 5b373a20f346018dd9cdf242e615e997b64d5803e77fd4fa434f346cb423366f199ee9597a3bf1515d238a16bf0e1cfc8178980d681e652a3352d78f003f1bbd
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.29.0 (2018-08-25)
6
+
7
+ * `RSpec/InstanceVariable` - Recommend local variables in addition to `let`. ([@jaredbeck][])
8
+ * Add `RSpec/ImplicitSubject` cop. ([@Darhazer][])
9
+ * Add `RSpec/HooksBeforeExamples` cop. ([@Darhazer][])
10
+
5
11
  ## 1.28.0 (2018-08-14)
6
12
 
7
13
  * Add `RSpec/ReceiveNever` cop enforcing usage of `not_to receive` instead of `never` matcher. ([@Darhazer][])
@@ -328,6 +334,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
328
334
  [@bquorning]: https://github.com/bquorning
329
335
  [@deivid-rodriguez]: https://github.com/deivid-rodriguez
330
336
  [@geniou]: https://github.com/geniou
337
+ [@jaredbeck]: https://github.com/jaredbeck
331
338
  [@jawshooah]: https://github.com/jawshooah
332
339
  [@nevir]: https://github.com/nevir
333
340
  [@nijikon]: https://github.com/nijikon
@@ -190,6 +190,11 @@ RSpec/HookArgument:
190
190
  - example
191
191
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HookArgument
192
192
 
193
+ RSpec/HooksBeforeExamples:
194
+ Enabled: true
195
+ Description: Checks for before/around/after hooks that come after an example.
196
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/HooksBeforeExamples
197
+
193
198
  RSpec/ImplicitExpect:
194
199
  Description: Check that a consistent implicit expectation style is used.
195
200
  Enabled: true
@@ -199,6 +204,15 @@ RSpec/ImplicitExpect:
199
204
  - should
200
205
  StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitExpect
201
206
 
207
+ RSpec/ImplicitSubject:
208
+ Enabled: true
209
+ Description: Checks for usage of implicit subject (`is_expected` / `should`).
210
+ EnforcedStyle: single_line_only
211
+ SupportedStyles:
212
+ - single_line_only
213
+ - disallow
214
+ StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject
215
+
202
216
  RSpec/InstanceSpy:
203
217
  Description: Checks for `instance_double` used with `have_received`.
204
218
  Enabled: true
@@ -115,7 +115,7 @@ module RuboCop
115
115
  if style == :described_class
116
116
  node.eql?(@described_class)
117
117
  else
118
- node.method_name == :described_class
118
+ node.send_type? && node.method_name == :described_class
119
119
  end
120
120
  end
121
121
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for before/around/after hooks that come after an example.
7
+ #
8
+ # @example
9
+ # # Bad
10
+ #
11
+ # it 'checks what foo does' do
12
+ # expect(foo).to be
13
+ # end
14
+ #
15
+ # before { prepare }
16
+ # after { clean_up }
17
+ #
18
+ # # Good
19
+ # before { prepare }
20
+ # after { clean_up }
21
+ #
22
+ # it 'checks what foo does' do
23
+ # expect(foo).to be
24
+ # end
25
+ #
26
+ class HooksBeforeExamples < Cop
27
+ include RangeHelp
28
+ include RuboCop::RSpec::FinalEndLocation
29
+
30
+ MSG = 'Move `%<hook>s` above the examples in the group.'.freeze
31
+
32
+ def_node_matcher :example_or_group?, <<-PATTERN
33
+ {
34
+ #{(Examples::ALL + ExampleGroups::ALL).block_pattern}
35
+ #{Includes::EXAMPLES.send_pattern}
36
+ }
37
+ PATTERN
38
+
39
+ def on_block(node)
40
+ return unless example_group_with_body?(node)
41
+
42
+ check_hooks(node.body) if multiline_block?(node.body)
43
+ end
44
+
45
+ def autocorrect(node)
46
+ lambda do |corrector|
47
+ first_example = find_first_example(node.parent)
48
+ first_example_pos = first_example.loc.expression
49
+ indent = "\n" + ' ' * first_example.loc.column
50
+
51
+ corrector.insert_before(first_example_pos, source(node) + indent)
52
+ corrector.remove(node_range_with_surrounding_space(node))
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def multiline_block?(block)
59
+ block.begin_type?
60
+ end
61
+
62
+ def check_hooks(node)
63
+ first_example = find_first_example(node)
64
+ return unless first_example
65
+
66
+ node.each_child_node do |child|
67
+ next if child.sibling_index < first_example.sibling_index
68
+ next unless hook?(child)
69
+
70
+ add_offense(
71
+ child,
72
+ message: format(MSG, hook: child.method_name)
73
+ )
74
+ end
75
+ end
76
+
77
+ def find_first_example(node)
78
+ node.children.find { |sibling| example_or_group?(sibling) }
79
+ end
80
+
81
+ def node_range_with_surrounding_space(node)
82
+ range = node_range(node)
83
+ range_by_whole_lines(range, include_final_newline: true)
84
+ end
85
+
86
+ def source(node)
87
+ node_range(node).source
88
+ end
89
+
90
+ def node_range(node)
91
+ range_between(
92
+ node.loc.expression.begin_pos,
93
+ final_end_location(node).end_pos
94
+ )
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Checks for usage of implicit subject (`is_expected` / `should`).
7
+ #
8
+ # This cop can be configured using the `EnforcedStyle` option
9
+ #
10
+ # @example `EnforcedStyle: single_line_only`
11
+ # # bad
12
+ # it do
13
+ # is_expected.to be_truthy
14
+ # end
15
+ #
16
+ # # good
17
+ # it { is_expected.to be_truthy }
18
+ # it do
19
+ # expect(subject).to be_truthy
20
+ # end
21
+ #
22
+ # @example `EnforcedStyle: disallow`
23
+ # # bad
24
+ # it { is_expected.to be_truthy }
25
+ #
26
+ # # good
27
+ # it { expect(subject).to be_truthy }
28
+ #
29
+ class ImplicitSubject < Cop
30
+ include ConfigurableEnforcedStyle
31
+
32
+ MSG = "Don't use implicit subject.".freeze
33
+
34
+ def_node_matcher :implicit_subject?, <<-PATTERN
35
+ (send nil? {:should :should_not :is_expected} ...)
36
+ PATTERN
37
+
38
+ def on_send(node)
39
+ return unless implicit_subject?(node)
40
+ return if valid_usage?(node)
41
+
42
+ add_offense(node)
43
+ end
44
+
45
+ def autocorrect(node)
46
+ replacement = 'expect(subject)'
47
+ if node.method_name == :should
48
+ replacement += '.to'
49
+ elsif node.method_name == :should_not
50
+ replacement += '.not_to'
51
+ end
52
+
53
+ ->(corrector) { corrector.replace(node.loc.selector, replacement) }
54
+ end
55
+
56
+ private
57
+
58
+ def valid_usage?(node)
59
+ return false unless style == :single_line_only
60
+ example = node.ancestors.find { |parent| example?(parent) }
61
+ example && example.single_line?
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  # end
48
48
  #
49
49
  class InstanceVariable < Cop
50
- MSG = 'Use `let` instead of an instance variable.'.freeze
50
+ MSG = 'Replace instance variable with local variable or `let`.'.freeze
51
51
 
52
52
  EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL
53
53
 
@@ -37,7 +37,9 @@ require_relative 'rspec/expect_output'
37
37
  require_relative 'rspec/file_path'
38
38
  require_relative 'rspec/focus'
39
39
  require_relative 'rspec/hook_argument'
40
+ require_relative 'rspec/hooks_before_examples'
40
41
  require_relative 'rspec/implicit_expect'
42
+ require_relative 'rspec/implicit_subject'
41
43
  require_relative 'rspec/instance_spy'
42
44
  require_relative 'rspec/instance_variable'
43
45
  require_relative 'rspec/invalid_predicate_matcher'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '1.28.0'.freeze
7
+ STRING = '1.29.0'.freeze
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,135 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::HooksBeforeExamples do
2
+ subject(:cop) { described_class.new }
3
+
4
+ it 'flags `before` after `it`' do
5
+ expect_offense(<<-RUBY)
6
+ RSpec.describe User do
7
+ it { is_expected.to be_after_let }
8
+ before { setup }
9
+ ^^^^^^^^^^^^^^^^ Move `before` above the examples in the group.
10
+ end
11
+ RUBY
12
+ end
13
+
14
+ it 'flags `before` after `context`' do
15
+ expect_offense(<<-RUBY)
16
+ RSpec.describe User do
17
+ context 'a context' do
18
+ it { is_expected.to be_after_let }
19
+ end
20
+
21
+ before { setup }
22
+ ^^^^^^^^^^^^^^^^ Move `before` above the examples in the group.
23
+ end
24
+ RUBY
25
+ end
26
+
27
+ it 'flags `before` after `include_examples`' do
28
+ expect_offense(<<-RUBY)
29
+ RSpec.describe User do
30
+ include_examples('should be after let')
31
+
32
+ before { setup }
33
+ ^^^^^^^^^^^^^^^^ Move `before` above the examples in the group.
34
+ end
35
+ RUBY
36
+ end
37
+
38
+ it 'flags `after` after an example' do
39
+ expect_offense(<<-RUBY)
40
+ RSpec.describe User do
41
+ it { is_expected.to be_after_let }
42
+ after { cleanup }
43
+ ^^^^^^^^^^^^^^^^^ Move `after` above the examples in the group.
44
+ end
45
+ RUBY
46
+ end
47
+
48
+ it 'flags scoped hook after an example' do
49
+ expect_offense(<<-RUBY)
50
+ RSpec.describe User do
51
+ it { is_expected.to be_after_let }
52
+ before(:each) { cleanup }
53
+ ^^^^^^^^^^^^^^^^^^^^^^^^^ Move `before` above the examples in the group.
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ it 'does not flag hooks before the examples' do
59
+ expect_no_offenses(<<-RUBY)
60
+ RSpec.describe User do
61
+ before(:each) { setup }
62
+ after(:each) { cleanup }
63
+
64
+ it { is_expected.to be_after_let }
65
+
66
+ context 'a context' do
67
+ it { is_expected.to work }
68
+ end
69
+
70
+ include_examples('everything is fine')
71
+ end
72
+ RUBY
73
+ end
74
+
75
+ it 'does not flag `before` in a nested context' do
76
+ expect_no_offenses(<<-RUBY)
77
+ RSpec.describe User do
78
+ before { setup }
79
+
80
+ context 'something else' do
81
+ before { additional_setup }
82
+ it { is_expected.to work }
83
+ end
84
+
85
+ include_examples('everything is fine')
86
+ end
87
+ RUBY
88
+ end
89
+
90
+ it 'allows inclusion of context before hooks' do
91
+ expect_no_offenses(<<-RUBY)
92
+ RSpec.describe User do
93
+ include_context 'special user'
94
+
95
+ before { setup }
96
+ end
97
+ RUBY
98
+ end
99
+
100
+ it 'ignores single-line example blocks' do
101
+ expect_no_offenses(<<-RUBY)
102
+ RSpec.describe User do
103
+ include_examples 'special user' do
104
+ before { setup }
105
+ end
106
+ end
107
+ RUBY
108
+ end
109
+
110
+ bad_code = <<-RUBY
111
+ RSpec.describe User do
112
+ include_examples('should be after hook')
113
+ context 'another one' do
114
+ before { another_setup }
115
+ include_examples('should be ok')
116
+ end
117
+
118
+ after { cleanup }
119
+ end
120
+ RUBY
121
+
122
+ good_code = <<-RUBY
123
+ RSpec.describe User do
124
+ after { cleanup }
125
+ include_examples('should be after hook')
126
+ context 'another one' do
127
+ before { another_setup }
128
+ include_examples('should be ok')
129
+ end
130
+
131
+ end
132
+ RUBY
133
+
134
+ include_examples 'autocorrect', bad_code, good_code
135
+ end
@@ -0,0 +1,142 @@
1
+ RSpec.describe RuboCop::Cop::RSpec::ImplicitSubject, :config do
2
+ subject(:cop) { described_class.new(config) }
3
+
4
+ let(:cop_config) do
5
+ { 'EnforcedStyle' => enforced_style }
6
+ end
7
+
8
+ context 'with EnforcedStyle `single_line_only`' do
9
+ let(:enforced_style) { 'single_line_only' }
10
+
11
+ it 'flags `is_expected` in multi-line examples' do
12
+ expect_offense(<<-RUBY)
13
+ it 'expect subject to be used' do
14
+ is_expected.to be_good
15
+ ^^^^^^^^^^^ Don't use implicit subject.
16
+ end
17
+ RUBY
18
+ end
19
+
20
+ it 'flags `should` in multi-line examples' do
21
+ expect_offense(<<-RUBY)
22
+ it 'expect subject to be used' do
23
+ should be_good
24
+ ^^^^^^^^^^^^^^ Don't use implicit subject.
25
+ end
26
+ RUBY
27
+ end
28
+
29
+ it 'allows `is_expected` in single-line examples' do
30
+ expect_no_offenses(<<-RUBY)
31
+ it { is_expected.to be_good }
32
+ RUBY
33
+ end
34
+
35
+ it 'allows `should` in single-line examples' do
36
+ expect_no_offenses(<<-RUBY)
37
+ it { should be_good }
38
+ RUBY
39
+ end
40
+
41
+ it 'does not flag methods called is_expected and should' do
42
+ expect_no_offenses(<<-RUBY)
43
+ it 'uses some similar sounding methods' do
44
+ expect(baz).to receive(:is_expected)
45
+ baz.is_expected
46
+ foo.should(deny_access)
47
+ end
48
+ RUBY
49
+ end
50
+
51
+ it 'detects usage of `is_expected` inside helper methods' do
52
+ expect_offense(<<-RUBY)
53
+ def permits(actions)
54
+ actions.each { |action| is_expected.to permit_action(action) }
55
+ ^^^^^^^^^^^ Don't use implicit subject.
56
+ end
57
+ RUBY
58
+ end
59
+
60
+ bad_code = <<-RUBY
61
+ it 'works' do
62
+ is_expected.to be_truthy
63
+ end
64
+ RUBY
65
+
66
+ good_code = <<-RUBY
67
+ it 'works' do
68
+ expect(subject).to be_truthy
69
+ end
70
+ RUBY
71
+
72
+ include_examples 'autocorrect',
73
+ bad_code,
74
+ good_code
75
+
76
+ bad_code = <<-RUBY
77
+ it 'works' do
78
+ should be_truthy
79
+ should_not be_falsy
80
+ end
81
+ RUBY
82
+
83
+ good_code = <<-RUBY
84
+ it 'works' do
85
+ expect(subject).to be_truthy
86
+ expect(subject).not_to be_falsy
87
+ end
88
+ RUBY
89
+
90
+ include_examples 'autocorrect',
91
+ bad_code,
92
+ good_code
93
+ end
94
+
95
+ context 'with EnforcedStyle `disallow`' do
96
+ let(:enforced_style) { 'disallow' }
97
+
98
+ it 'flags `is_expected` in multi-line examples' do
99
+ expect_offense(<<-RUBY)
100
+ it 'expect subject to be used' do
101
+ is_expected.to be_good
102
+ ^^^^^^^^^^^ Don't use implicit subject.
103
+ end
104
+ RUBY
105
+ end
106
+
107
+ it 'flags `is_expected` in single-line examples' do
108
+ expect_offense(<<-RUBY)
109
+ it { is_expected.to be_good }
110
+ ^^^^^^^^^^^ Don't use implicit subject.
111
+ RUBY
112
+ end
113
+
114
+ it 'flags `should` in multi-line examples' do
115
+ expect_offense(<<-RUBY)
116
+ it 'expect subject to be used' do
117
+ should be_good
118
+ ^^^^^^^^^^^^^^ Don't use implicit subject.
119
+ end
120
+ RUBY
121
+ end
122
+
123
+ it 'flags `should` in single-line examples' do
124
+ expect_offense(<<-RUBY)
125
+ it { should be_good }
126
+ ^^^^^^^^^^^^^^ Don't use implicit subject.
127
+ RUBY
128
+ end
129
+
130
+ include_examples 'autocorrect',
131
+ 'it { is_expected.to be_truthy }',
132
+ 'it { expect(subject).to be_truthy }'
133
+
134
+ include_examples 'autocorrect',
135
+ 'it { should be_truthy }',
136
+ 'it { expect(subject).to be_truthy }'
137
+
138
+ include_examples 'autocorrect',
139
+ 'it { should_not be_truthy }',
140
+ 'it { expect(subject).not_to be_truthy }'
141
+ end
142
+ end
@@ -6,7 +6,7 @@ RSpec.describe RuboCop::Cop::RSpec::InstanceVariable do
6
6
  describe MyClass do
7
7
  before { @foo = [] }
8
8
  it { expect(@foo).to be_empty }
9
- ^^^^ Use `let` instead of an instance variable.
9
+ ^^^^ Replace instance variable with local variable or `let`.
10
10
  end
11
11
  RUBY
12
12
  end
@@ -24,7 +24,7 @@ RSpec.describe RuboCop::Cop::RSpec::InstanceVariable do
24
24
  expect_offense(<<-RUBY)
25
25
  shared_examples 'shared example' do
26
26
  it { expect(@foo).to be_empty }
27
- ^^^^ Use `let` instead of an instance variable.
27
+ ^^^^ Replace instance variable with local variable or `let`.
28
28
  end
29
29
  RUBY
30
30
  end
@@ -77,7 +77,7 @@ RSpec.describe RuboCop::Cop::RSpec::InstanceVariable do
77
77
  describe MyClass do
78
78
  before { @foo = [] }
79
79
  it { expect(@foo).to be_empty }
80
- ^^^^ Use `let` instead of an instance variable.
80
+ ^^^^ Replace instance variable with local variable or `let`.
81
81
  end
82
82
  RUBY
83
83
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.28.0
4
+ version: 1.29.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Backus
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-08-14 00:00:00.000000000 Z
13
+ date: 2018-08-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -148,7 +148,9 @@ files:
148
148
  - lib/rubocop/cop/rspec/file_path.rb
149
149
  - lib/rubocop/cop/rspec/focus.rb
150
150
  - lib/rubocop/cop/rspec/hook_argument.rb
151
+ - lib/rubocop/cop/rspec/hooks_before_examples.rb
151
152
  - lib/rubocop/cop/rspec/implicit_expect.rb
153
+ - lib/rubocop/cop/rspec/implicit_subject.rb
152
154
  - lib/rubocop/cop/rspec/instance_spy.rb
153
155
  - lib/rubocop/cop/rspec/instance_variable.rb
154
156
  - lib/rubocop/cop/rspec/invalid_predicate_matcher.rb
@@ -241,7 +243,9 @@ files:
241
243
  - spec/rubocop/cop/rspec/file_path_spec.rb
242
244
  - spec/rubocop/cop/rspec/focus_spec.rb
243
245
  - spec/rubocop/cop/rspec/hook_argument_spec.rb
246
+ - spec/rubocop/cop/rspec/hooks_before_examples_spec.rb
244
247
  - spec/rubocop/cop/rspec/implicit_expect_spec.rb
248
+ - spec/rubocop/cop/rspec/implicit_subject_spec.rb
245
249
  - spec/rubocop/cop/rspec/instance_spy_spec.rb
246
250
  - spec/rubocop/cop/rspec/instance_variable_spec.rb
247
251
  - spec/rubocop/cop/rspec/invalid_predicate_matcher_spec.rb
@@ -356,7 +360,9 @@ test_files:
356
360
  - spec/rubocop/cop/rspec/file_path_spec.rb
357
361
  - spec/rubocop/cop/rspec/focus_spec.rb
358
362
  - spec/rubocop/cop/rspec/hook_argument_spec.rb
363
+ - spec/rubocop/cop/rspec/hooks_before_examples_spec.rb
359
364
  - spec/rubocop/cop/rspec/implicit_expect_spec.rb
365
+ - spec/rubocop/cop/rspec/implicit_subject_spec.rb
360
366
  - spec/rubocop/cop/rspec/instance_spy_spec.rb
361
367
  - spec/rubocop/cop/rspec/instance_variable_spec.rb
362
368
  - spec/rubocop/cop/rspec/invalid_predicate_matcher_spec.rb