rubocop-rspec 1.28.0 → 1.29.0

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: 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