rubocop-rspec 3.4.0 → 3.6.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/CHANGELOG.md +17 -0
- data/README.md +7 -4
- data/config/default.yml +6 -0
- data/lib/rubocop/cop/rspec/be_eq.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/be_nil.rb +4 -0
- data/lib/rubocop/cop/rspec/change_by_zero.rb +3 -4
- data/lib/rubocop/cop/rspec/context_wording.rb +6 -1
- data/lib/rubocop/cop/rspec/described_class.rb +4 -2
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +4 -4
- data/lib/rubocop/cop/rspec/example_wording.rb +1 -3
- data/lib/rubocop/cop/rspec/excessive_docstring_spacing.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_change.rb +21 -2
- data/lib/rubocop/cop/rspec/focus.rb +15 -11
- data/lib/rubocop/cop/rspec/hook_argument.rb +2 -2
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_expect.rb +3 -3
- data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -0
- data/lib/rubocop/cop/rspec/include_examples.rb +39 -0
- data/lib/rubocop/cop/rspec/indexed_let.rb +2 -0
- data/lib/rubocop/cop/rspec/message_spies.rb +4 -0
- data/lib/rubocop/cop/rspec/nested_groups.rb +2 -2
- data/lib/rubocop/cop/rspec/no_expectation_example.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/pending_without_reason.rb +2 -3
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +18 -8
- data/lib/rubocop/cop/rspec/receive_messages.rb +1 -2
- data/lib/rubocop/cop/rspec/redundant_around.rb +1 -1
- data/lib/rubocop/cop/rspec/return_from_stub.rb +5 -4
- data/lib/rubocop/cop/rspec/scattered_setup.rb +10 -2
- data/lib/rubocop/cop/rspec/variable_definition.rb +1 -1
- data/lib/rubocop/cop/rspec/variable_name.rb +1 -1
- data/lib/rubocop/cop/rspec_cops.rb +1 -0
- data/lib/rubocop/rspec/config_formatter.rb +4 -9
- data/lib/rubocop/rspec/hook.rb +3 -1
- data/lib/rubocop/rspec/language.rb +3 -6
- data/lib/rubocop/rspec/plugin.rb +37 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/lib/rubocop/rspec/wording.rb +0 -2
- data/lib/rubocop/rspec.rb +0 -7
- data/lib/rubocop-rspec.rb +1 -3
- metadata +28 -6
- data/lib/rubocop/rspec/inject.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e4727f136d1a399d3108fd010c76ac61f7fce57e3c89cb2d97ad121d558af44
|
4
|
+
data.tar.gz: dcc8c7f61c420d5938807dae3a610f53c6be8c657687e38542f701db2aec4ce2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 651f8b53a0b70738f9dc084df5bdf471ce65ae4d7f0c2db8cc2eb557178fd541f317bee36ae062b8109aed72b452f69eb1c965db923d5d9875c86de9ab84f23e
|
7
|
+
data.tar.gz: f189ec83b4b663df4e3aca303f2f273fded6d5529e689d7f9421f379dd46203da95236a4f649414466b0f6050b0d9e7d952df003b4b63ed45722c1764fd1a094
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
## Master (Unreleased)
|
4
4
|
|
5
|
+
## 3.6.0 (2025-04-18)
|
6
|
+
|
7
|
+
- Fix false positive in `RSpec/Pending`, where it would mark the default block `it` as an offense. ([@bquorning])
|
8
|
+
- Fix issue when `Style/ContextWording` is configured with a Prefix being interpreted as a boolean, like `on`. ([@sakuro])
|
9
|
+
- Add new `RSpec/IncludeExamples` cop to enforce using `it_behaves_like` over `include_examples`. ([@dvandersluis])
|
10
|
+
- Change `RSpec/ScatteredSetup` to allow `around` hooks to be scattered. ([@ydah])
|
11
|
+
- Fix an error `RSpec/ChangeByZero` cop when without expect block. ([@lee266])
|
12
|
+
- Fix a false positive for `RSpec/DescribedClass` when `SkipBlocks` is true and numblocks are used. ([@earlopain])
|
13
|
+
|
14
|
+
## 3.5.0 (2025-02-16)
|
15
|
+
|
16
|
+
- Don't let `RSpec/PredicateMatcher` replace `respond_to?` with two arguments with the RSpec `respond_to` matcher. ([@bquorning])
|
17
|
+
- Fix `RSpec/PredicateMatcher` support for `eql` and `equal` matchers. ([@bquorning])
|
18
|
+
- Pluginfy RuboCop RSpec. ([@koic])
|
19
|
+
|
5
20
|
## 3.4.0 (2025-01-20)
|
6
21
|
|
7
22
|
- Fix `RSpec/SortMetadata` cop to limit sorting to trailing metadata arguments. ([@cbliard])
|
@@ -992,6 +1007,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
992
1007
|
[@krororo]: https://github.com/krororo
|
993
1008
|
[@kuahyeow]: https://github.com/kuahyeow
|
994
1009
|
[@lazycoder9]: https://github.com/lazycoder9
|
1010
|
+
[@lee266]: https://github.com/lee266
|
995
1011
|
[@leoarnold]: https://github.com/leoarnold
|
996
1012
|
[@liberatys]: https://github.com/Liberatys
|
997
1013
|
[@lokhi]: https://github.com/lokhi
|
@@ -1032,6 +1048,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
|
|
1032
1048
|
[@rrosenblum]: https://github.com/rrosenblum
|
1033
1049
|
[@rspeicher]: https://github.com/rspeicher
|
1034
1050
|
[@rst-j]: https://github.com/RST-J
|
1051
|
+
[@sakuro]: https://github.com/sakuro
|
1035
1052
|
[@samrjenkins]: https://github.com/samrjenkins
|
1036
1053
|
[@schmijos]: https://github.com/schmijos
|
1037
1054
|
[@seanpdoyle]: https://github.com/seanpdoyle
|
data/README.md
CHANGED
@@ -48,13 +48,13 @@ ways to do this:
|
|
48
48
|
Put this into your `.rubocop.yml`.
|
49
49
|
|
50
50
|
```yaml
|
51
|
-
|
51
|
+
plugins: rubocop-rspec
|
52
52
|
```
|
53
53
|
|
54
54
|
Alternatively, use the following array notation when specifying multiple extensions.
|
55
55
|
|
56
56
|
```yaml
|
57
|
-
|
57
|
+
plugins:
|
58
58
|
- rubocop-other-extension
|
59
59
|
- rubocop-rspec
|
60
60
|
```
|
@@ -62,17 +62,20 @@ require:
|
|
62
62
|
Now you can run `rubocop` and it will automatically load the RuboCop RSpec
|
63
63
|
cops together with the standard cops.
|
64
64
|
|
65
|
+
> [!NOTE]
|
66
|
+
> The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
|
67
|
+
|
65
68
|
### Command line
|
66
69
|
|
67
70
|
```bash
|
68
|
-
rubocop --
|
71
|
+
rubocop --plugin rubocop-rspec
|
69
72
|
```
|
70
73
|
|
71
74
|
### Rake task
|
72
75
|
|
73
76
|
```ruby
|
74
77
|
RuboCop::RakeTask.new do |task|
|
75
|
-
task.
|
78
|
+
task.plugins << 'rubocop-rspec'
|
76
79
|
end
|
77
80
|
```
|
78
81
|
|
data/config/default.yml
CHANGED
@@ -532,6 +532,12 @@ RSpec/ImplicitSubject:
|
|
532
532
|
VersionChanged: '2.13'
|
533
533
|
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ImplicitSubject
|
534
534
|
|
535
|
+
RSpec/IncludeExamples:
|
536
|
+
Description: Checks for usage of `include_examples`.
|
537
|
+
Enabled: pending
|
538
|
+
VersionAdded: '3.6'
|
539
|
+
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/IncludeExamples
|
540
|
+
|
535
541
|
RSpec/IndexedLet:
|
536
542
|
Description: Do not set up test data using indexes (e.g., `item_1`, `item_2`).
|
537
543
|
Enabled: true
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
|
46
46
|
# @!method eql_type_with_identity(node)
|
47
47
|
def_node_matcher :eql_type_with_identity, <<~PATTERN
|
48
|
-
(send _ :to $(send nil? :eql {
|
48
|
+
(send _ :to $(send nil? :eql {boolean int float sym nil}))
|
49
49
|
PATTERN
|
50
50
|
|
51
51
|
def on_send(node)
|
@@ -101,8 +101,9 @@ module RuboCop
|
|
101
101
|
|
102
102
|
private
|
103
103
|
|
104
|
-
# rubocop:disable Metrics/MethodLength
|
105
104
|
def register_offense(node, change_node)
|
105
|
+
return unless node.parent.send_type?
|
106
|
+
|
106
107
|
if compound_expectations?(node)
|
107
108
|
add_offense(node,
|
108
109
|
message: message_compound(change_node)) do |corrector|
|
@@ -115,11 +116,9 @@ module RuboCop
|
|
115
116
|
end
|
116
117
|
end
|
117
118
|
end
|
118
|
-
# rubocop:enable Metrics/MethodLength
|
119
119
|
|
120
120
|
def compound_expectations?(node)
|
121
|
-
node.parent.
|
122
|
-
%i[and or & |].include?(node.parent.method_name)
|
121
|
+
%i[and or & |].include?(node.parent.method_name)
|
123
122
|
end
|
124
123
|
|
125
124
|
def message(change_node)
|
@@ -115,7 +115,12 @@ module RuboCop
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def prefixes
|
118
|
-
Array(cop_config.fetch('Prefixes', []))
|
118
|
+
Array(cop_config.fetch('Prefixes', [])).tap do |prefixes|
|
119
|
+
non_strings = prefixes.reject { |pre| pre.is_a?(String) }
|
120
|
+
unless non_strings.empty?
|
121
|
+
raise "Non-string prefixes #{non_strings.inspect} detected."
|
122
|
+
end
|
123
|
+
end
|
119
124
|
end
|
120
125
|
end
|
121
126
|
end
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
83
83
|
|
84
84
|
# @!method rspec_block?(node)
|
85
85
|
def_node_matcher :rspec_block?,
|
86
|
-
'(
|
86
|
+
'(any_block (send #rspec? #ALL.all ...) ...)'
|
87
87
|
|
88
88
|
# @!method scope_changing_syntax?(node)
|
89
89
|
def_node_matcher :scope_changing_syntax?, '{def class module}'
|
@@ -153,7 +153,9 @@ module RuboCop
|
|
153
153
|
end
|
154
154
|
|
155
155
|
def skippable_block?(node)
|
156
|
-
|
156
|
+
return false unless cop_config['SkipBlocks']
|
157
|
+
|
158
|
+
node.any_block_type? && !rspec_block?(node)
|
157
159
|
end
|
158
160
|
|
159
161
|
def only_static_constants?
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
|
25
25
|
# @!method include_rspec_blocks?(node)
|
26
26
|
def_node_search :include_rspec_blocks?, <<~PATTERN
|
27
|
-
(
|
27
|
+
(any_block (send #explicit_rspec? #ExampleGroups.all ...) ...)
|
28
28
|
PATTERN
|
29
29
|
|
30
30
|
def on_module(node)
|
@@ -137,7 +137,7 @@ module RuboCop
|
|
137
137
|
PATTERN
|
138
138
|
|
139
139
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
140
|
-
return if node.each_ancestor(:
|
140
|
+
return if node.each_ancestor(:any_def).any?
|
141
141
|
return if node.each_ancestor(:block).any? { |block| example?(block) }
|
142
142
|
|
143
143
|
example_group_body(node) do |body|
|
@@ -155,7 +155,7 @@ module RuboCop
|
|
155
155
|
return true unless body
|
156
156
|
return false if conditionals_with_examples?(body)
|
157
157
|
|
158
|
-
if body.
|
158
|
+
if body.type?(:if, :case)
|
159
159
|
!examples_in_branches?(body)
|
160
160
|
else
|
161
161
|
!examples?(body)
|
@@ -163,7 +163,7 @@ module RuboCop
|
|
163
163
|
end
|
164
164
|
|
165
165
|
def conditionals_with_examples?(body)
|
166
|
-
return false unless body.
|
166
|
+
return false unless body.type?(:begin, :case)
|
167
167
|
|
168
168
|
body.each_descendant(:if, :case).any? do |condition_node|
|
169
169
|
examples_in_branches?(condition_node)
|
@@ -172,7 +172,7 @@ module RuboCop
|
|
172
172
|
|
173
173
|
def examples_in_branches?(condition_node)
|
174
174
|
return false unless condition_node
|
175
|
-
return false
|
175
|
+
return false unless condition_node.type?(:if, :case)
|
176
176
|
|
177
177
|
condition_node.branches.any? { |branch| examples?(branch) }
|
178
178
|
end
|
@@ -67,7 +67,6 @@ module RuboCop
|
|
67
67
|
} ...) ...)
|
68
68
|
PATTERN
|
69
69
|
|
70
|
-
# rubocop:disable Metrics/MethodLength
|
71
70
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
72
71
|
it_description(node) do |description_node, message|
|
73
72
|
if message.match?(SHOULD_PREFIX)
|
@@ -82,7 +81,6 @@ module RuboCop
|
|
82
81
|
end
|
83
82
|
end
|
84
83
|
end
|
85
|
-
# rubocop:enable Metrics/MethodLength
|
86
84
|
|
87
85
|
private
|
88
86
|
|
@@ -128,7 +126,7 @@ module RuboCop
|
|
128
126
|
node.node_parts.map { |child_node| text(child_node) }.join
|
129
127
|
when :str
|
130
128
|
node.value
|
131
|
-
|
129
|
+
else
|
132
130
|
node.source
|
133
131
|
end
|
134
132
|
end
|
@@ -5,11 +5,30 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks for consistent style of change matcher.
|
7
7
|
#
|
8
|
-
# Enforces either passing
|
9
|
-
# or
|
8
|
+
# Enforces either passing a receiver and message as method arguments,
|
9
|
+
# or a block.
|
10
10
|
#
|
11
11
|
# This cop can be configured using the `EnforcedStyle` option.
|
12
12
|
#
|
13
|
+
# @safety
|
14
|
+
# Autocorrection is unsafe because `method_call` style calls the
|
15
|
+
# receiver *once* and sends the message to it before and after
|
16
|
+
# calling the `expect` block, whereas `block` style calls the
|
17
|
+
# expression *twice*, including the receiver.
|
18
|
+
#
|
19
|
+
# If your receiver is dynamic (e.g., the result of a method call) and
|
20
|
+
# you expect it to be called before and after the `expect` block,
|
21
|
+
# changing from `block` to `method_call` style may break your test.
|
22
|
+
#
|
23
|
+
# [source,ruby]
|
24
|
+
# ----
|
25
|
+
# expect { run }.to change { my_method.message }
|
26
|
+
# # `my_method` is called before and after `run`
|
27
|
+
#
|
28
|
+
# expect { run }.to change(my_method, :message)
|
29
|
+
# # `my_method` is called once, but `message` is called on it twice
|
30
|
+
# ----
|
31
|
+
#
|
13
32
|
# @example `EnforcedStyle: method_call` (default)
|
14
33
|
# # bad
|
15
34
|
# expect { run }.to change { Foo.bar }
|
@@ -73,25 +73,29 @@ module RuboCop
|
|
73
73
|
PATTERN
|
74
74
|
|
75
75
|
def on_send(node)
|
76
|
-
return if node.chained? || node.each_ancestor(:
|
76
|
+
return if node.chained? || node.each_ancestor(:any_def).any?
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
correct_send(corrector, focus)
|
84
|
-
end
|
78
|
+
if focused_block?(node)
|
79
|
+
on_focused_block(node)
|
80
|
+
else
|
81
|
+
metadata(node) do |focus|
|
82
|
+
on_metadata(focus)
|
85
83
|
end
|
86
84
|
end
|
87
85
|
end
|
88
86
|
|
89
87
|
private
|
90
88
|
|
91
|
-
def
|
92
|
-
|
89
|
+
def on_focused_block(node)
|
90
|
+
add_offense(node) do |corrector|
|
91
|
+
correct_send(corrector, node)
|
92
|
+
end
|
93
|
+
end
|
93
94
|
|
94
|
-
|
95
|
+
def on_metadata(node)
|
96
|
+
add_offense(node) do |corrector|
|
97
|
+
corrector.remove(with_surrounding(node))
|
98
|
+
end
|
95
99
|
end
|
96
100
|
|
97
101
|
def with_surrounding(focus)
|
@@ -67,12 +67,12 @@ module RuboCop
|
|
67
67
|
|
68
68
|
# @!method scoped_hook(node)
|
69
69
|
def_node_matcher :scoped_hook, <<~PATTERN
|
70
|
-
(
|
70
|
+
(any_block $(send _ #Hooks.all (sym ${:each :example})) ...)
|
71
71
|
PATTERN
|
72
72
|
|
73
73
|
# @!method unscoped_hook(node)
|
74
74
|
def_node_matcher :unscoped_hook, <<~PATTERN
|
75
|
-
(
|
75
|
+
(any_block $(send _ #Hooks.all) ...)
|
76
76
|
PATTERN
|
77
77
|
|
78
78
|
def on_block(node)
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
|
47
47
|
ENFORCED_REPLACEMENTS = alternatives.merge(alternatives.invert).freeze
|
48
48
|
|
49
|
-
def on_send(node)
|
49
|
+
def on_send(node)
|
50
50
|
return unless (source_range = offending_expect(node))
|
51
51
|
|
52
52
|
expectation_source = source_range.source
|
@@ -69,13 +69,13 @@ module RuboCop
|
|
69
69
|
def offending_expect(node)
|
70
70
|
case implicit_expect(node)
|
71
71
|
when :is_expected
|
72
|
-
|
72
|
+
range_for_is_expected(node.loc)
|
73
73
|
when :should, :should_not
|
74
74
|
node.loc.selector
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
def
|
78
|
+
def range_for_is_expected(source_map)
|
79
79
|
Parser::Source::Range.new(
|
80
80
|
source_map.expression.source_buffer,
|
81
81
|
source_map.expression.begin_pos,
|
@@ -107,6 +107,10 @@ module RuboCop
|
|
107
107
|
corrector.replace(node.location.selector, 'expect(subject).to')
|
108
108
|
when :should_not
|
109
109
|
corrector.replace(node.location.selector, 'expect(subject).not_to')
|
110
|
+
else
|
111
|
+
# :nocov:
|
112
|
+
:noop
|
113
|
+
# :nocov:
|
110
114
|
end
|
111
115
|
end
|
112
116
|
|
@@ -129,6 +133,10 @@ module RuboCop
|
|
129
133
|
implicit_subject_in_non_its_and_non_single_line?(node)
|
130
134
|
when :single_statement_only
|
131
135
|
implicit_subject_in_non_its_and_non_single_statement?(node)
|
136
|
+
else
|
137
|
+
# :nocov:
|
138
|
+
:noop
|
139
|
+
# :nocov:
|
132
140
|
end
|
133
141
|
end
|
134
142
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for usage of `include_examples`.
|
7
|
+
#
|
8
|
+
# `include_examples`, unlike `it_behaves_like`, does not create its
|
9
|
+
# own context. As such, using `subject`, `let`, `before`/`after`, etc.
|
10
|
+
# within shared examples included with `include_examples` can have
|
11
|
+
# unexpected behavior and side effects.
|
12
|
+
#
|
13
|
+
# Prefer using `it_behaves_like` instead.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# # bad
|
17
|
+
# include_examples 'examples'
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# it_behaves_like 'examples'
|
21
|
+
#
|
22
|
+
class IncludeExamples < Base
|
23
|
+
extend AutoCorrector
|
24
|
+
|
25
|
+
MSG = 'Prefer `it_behaves_like` over `include_examples`.'
|
26
|
+
|
27
|
+
RESTRICT_ON_SEND = %i[include_examples].freeze
|
28
|
+
|
29
|
+
def on_send(node)
|
30
|
+
selector = node.loc.selector
|
31
|
+
|
32
|
+
add_offense(selector) do |corrector|
|
33
|
+
corrector.replace(selector, 'it_behaves_like')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -133,8 +133,8 @@ module RuboCop
|
|
133
133
|
|
134
134
|
def count_up_nesting?(node, example_group)
|
135
135
|
example_group &&
|
136
|
-
|
137
|
-
!allowed_groups.include?(node.method_name.to_s)
|
136
|
+
node.block_type? &&
|
137
|
+
!allowed_groups.include?(node.method_name.to_s)
|
138
138
|
end
|
139
139
|
|
140
140
|
def message(nesting)
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
# @param [RuboCop::AST::Node] node
|
66
66
|
# @return [Boolean]
|
67
67
|
def_node_matcher :regular_or_focused_example?, <<~PATTERN
|
68
|
-
(
|
68
|
+
(any_block (send nil? {#Examples.regular #Examples.focused} ...) ...)
|
69
69
|
PATTERN
|
70
70
|
|
71
71
|
# @!method includes_expectation?(node)
|
@@ -63,8 +63,7 @@ module RuboCop
|
|
63
63
|
def_node_matcher :skipped_in_example?, <<~PATTERN
|
64
64
|
{
|
65
65
|
(send nil? ${#Examples.skipped #Examples.pending})
|
66
|
-
(
|
67
|
-
(numblock (send nil? ${#Examples.skipped}) ...)
|
66
|
+
(any_block (send nil? ${#Examples.skipped}) ...)
|
68
67
|
}
|
69
68
|
PATTERN
|
70
69
|
|
@@ -75,7 +74,7 @@ module RuboCop
|
|
75
74
|
|
76
75
|
# @!method skipped_by_example_method_with_block?(node)
|
77
76
|
def_node_matcher :skipped_by_example_method_with_block?, <<~PATTERN
|
78
|
-
(
|
77
|
+
(any_block (send nil? ${#Examples.skipped #Examples.pending} ...) ...)
|
79
78
|
PATTERN
|
80
79
|
|
81
80
|
# @!method metadata_without_reason?(node)
|
@@ -15,6 +15,8 @@ module RuboCop
|
|
15
15
|
|
16
16
|
def check_inflected(node)
|
17
17
|
predicate_in_actual?(node) do |predicate, to, matcher|
|
18
|
+
next if cannot_replace_predicate?(predicate)
|
19
|
+
|
18
20
|
msg = message_inflected(predicate)
|
19
21
|
add_offense(node, message: msg) do |corrector|
|
20
22
|
remove_predicate(corrector, predicate)
|
@@ -35,9 +37,13 @@ module RuboCop
|
|
35
37
|
$#boolean_matcher? ...)
|
36
38
|
PATTERN
|
37
39
|
|
40
|
+
def cannot_replace_predicate?(send_node)
|
41
|
+
send_node.method?(:respond_to?) && send_node.arguments.length > 1
|
42
|
+
end
|
43
|
+
|
38
44
|
# @!method be_bool?(node)
|
39
45
|
def_node_matcher :be_bool?, <<~PATTERN
|
40
|
-
(send nil? {:be :eq :eql :equal}
|
46
|
+
(send nil? {:be :eq :eql :equal} boolean)
|
41
47
|
PATTERN
|
42
48
|
|
43
49
|
# @!method be_boolthy?(node)
|
@@ -63,7 +69,6 @@ module RuboCop
|
|
63
69
|
matcher_name: to_predicate_matcher(predicate.method_name))
|
64
70
|
end
|
65
71
|
|
66
|
-
# rubocop:disable Metrics/MethodLength
|
67
72
|
def to_predicate_matcher(name)
|
68
73
|
case name = name.to_s
|
69
74
|
when 'is_a?'
|
@@ -80,7 +85,6 @@ module RuboCop
|
|
80
85
|
"be_#{name[0..-2]}"
|
81
86
|
end
|
82
87
|
end
|
83
|
-
# rubocop:enable Metrics/MethodLength
|
84
88
|
|
85
89
|
def remove_predicate(corrector, predicate)
|
86
90
|
range = predicate.loc.dot.with(
|
@@ -106,12 +110,16 @@ module RuboCop
|
|
106
110
|
|
107
111
|
def true?(to_symbol, matcher)
|
108
112
|
result = case matcher.method_name
|
109
|
-
when :be, :eq
|
113
|
+
when :be, :eq, :eql, :equal
|
110
114
|
matcher.first_argument.true_type?
|
111
115
|
when :be_truthy, :a_truthy_value
|
112
116
|
true
|
113
117
|
when :be_falsey, :be_falsy, :a_falsey_value, :a_falsy_value
|
114
118
|
false
|
119
|
+
else
|
120
|
+
# :nocov:
|
121
|
+
:noop
|
122
|
+
# :nocov:
|
115
123
|
end
|
116
124
|
to_symbol == :to ? result : !result
|
117
125
|
end
|
@@ -174,7 +182,7 @@ module RuboCop
|
|
174
182
|
|
175
183
|
def heredoc_argument?(matcher)
|
176
184
|
matcher.arguments.select do |arg|
|
177
|
-
arg.
|
185
|
+
arg.type?(:str, :dstr, :xstr)
|
178
186
|
end.any?(&:heredoc?)
|
179
187
|
end
|
180
188
|
|
@@ -233,7 +241,6 @@ module RuboCop
|
|
233
241
|
corrector.insert_after(actual, ".#{predicate}" + args + block)
|
234
242
|
end
|
235
243
|
|
236
|
-
# rubocop:disable Metrics/MethodLength
|
237
244
|
def to_predicate_method(matcher)
|
238
245
|
case matcher = matcher.to_s
|
239
246
|
when 'be_a', 'be_an', 'be_a_kind_of', 'a_kind_of', 'be_kind_of'
|
@@ -250,7 +257,6 @@ module RuboCop
|
|
250
257
|
"#{matcher[/\Abe_(.+)/, 1]}?"
|
251
258
|
end
|
252
259
|
end
|
253
|
-
# rubocop:enable Metrics/MethodLength
|
254
260
|
|
255
261
|
def replacement_matcher(node)
|
256
262
|
case [cop_config['Strict'], node.method?(:to)]
|
@@ -260,7 +266,7 @@ module RuboCop
|
|
260
266
|
'be(false)'
|
261
267
|
when [false, true]
|
262
268
|
'be_truthy'
|
263
|
-
|
269
|
+
else
|
264
270
|
'be_falsey'
|
265
271
|
end
|
266
272
|
end
|
@@ -329,6 +335,10 @@ module RuboCop
|
|
329
335
|
check_inflected(node)
|
330
336
|
when :explicit
|
331
337
|
check_explicit(node)
|
338
|
+
else
|
339
|
+
# :nocov:
|
340
|
+
:noop
|
341
|
+
# :nocov:
|
332
342
|
end
|
333
343
|
end
|
334
344
|
|
@@ -148,8 +148,7 @@ module RuboCop
|
|
148
148
|
end
|
149
149
|
|
150
150
|
def heredoc_or_splat?(node)
|
151
|
-
(
|
152
|
-
node.splat_type?
|
151
|
+
(node.type?(:str, :dstr) && node.heredoc?) || node.splat_type?
|
153
152
|
end
|
154
153
|
|
155
154
|
def requires_quotes?(value)
|
@@ -41,7 +41,7 @@ module RuboCop
|
|
41
41
|
|
42
42
|
# @!method match_redundant_around_hook_block?(node)
|
43
43
|
def_node_matcher :match_redundant_around_hook_block?, <<~PATTERN
|
44
|
-
(
|
44
|
+
(any_block (send _ :around ...) ... (send _ :run))
|
45
45
|
PATTERN
|
46
46
|
|
47
47
|
# @!method match_redundant_around_hook_send?(node)
|
@@ -80,10 +80,10 @@ module RuboCop
|
|
80
80
|
|
81
81
|
def check_block_body(block)
|
82
82
|
body = block.body
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
return if dynamic?(body)
|
84
|
+
|
85
|
+
add_offense(block.loc.begin, message: MSG_AND_RETURN) do |corrector|
|
86
|
+
BlockBodyCorrector.new(block).call(corrector)
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -162,6 +162,7 @@ module RuboCop
|
|
162
162
|
end
|
163
163
|
|
164
164
|
NULL_BLOCK_BODY = Struct.new(:loc, :source).new(nil, 'nil')
|
165
|
+
private_constant :NULL_BLOCK_BODY
|
165
166
|
end
|
166
167
|
end
|
167
168
|
end
|
@@ -5,7 +5,9 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks for setup scattered across multiple hooks in an example group.
|
7
7
|
#
|
8
|
-
# Unify `before
|
8
|
+
# Unify `before` and `after` hooks when possible.
|
9
|
+
# However, `around` hooks are allowed to be defined multiple times,
|
10
|
+
# as unifying them would typically make the code harder to read.
|
9
11
|
#
|
10
12
|
# @example
|
11
13
|
# # bad
|
@@ -22,6 +24,12 @@ module RuboCop
|
|
22
24
|
# end
|
23
25
|
# end
|
24
26
|
#
|
27
|
+
# # good
|
28
|
+
# describe Foo do
|
29
|
+
# around { |example| before1; example.call; after1 }
|
30
|
+
# around { |example| before2; example.call; after2 }
|
31
|
+
# end
|
32
|
+
#
|
25
33
|
class ScatteredSetup < Base
|
26
34
|
include FinalEndLocation
|
27
35
|
include RangeHelp
|
@@ -48,7 +56,7 @@ module RuboCop
|
|
48
56
|
def repeated_hooks(node)
|
49
57
|
hooks = RuboCop::RSpec::ExampleGroup.new(node)
|
50
58
|
.hooks
|
51
|
-
.select
|
59
|
+
.select { |hook| hook.knowable_scope? && hook.name != :around }
|
52
60
|
.group_by { |hook| [hook.name, hook.scope, hook.metadata] }
|
53
61
|
.values
|
54
62
|
.reject(&:one?)
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
return unless inside_example_group?(node)
|
51
51
|
|
52
52
|
variable_definition?(node) do |variable|
|
53
|
-
return if variable.
|
53
|
+
return if variable.type?(:dstr, :dsym)
|
54
54
|
return if matches_allowed_pattern?(variable.value)
|
55
55
|
|
56
56
|
check_name(node, variable.value, variable.source_range)
|
@@ -48,6 +48,7 @@ require_relative 'rspec/identical_equality_assertion'
|
|
48
48
|
require_relative 'rspec/implicit_block_expectation'
|
49
49
|
require_relative 'rspec/implicit_expect'
|
50
50
|
require_relative 'rspec/implicit_subject'
|
51
|
+
require_relative 'rspec/include_examples'
|
51
52
|
require_relative 'rspec/indexed_let'
|
52
53
|
require_relative 'rspec/instance_spy'
|
53
54
|
require_relative 'rspec/instance_variable'
|
@@ -6,9 +6,7 @@ module RuboCop
|
|
6
6
|
module RSpec
|
7
7
|
# Builds a YAML config file from two config hashes
|
8
8
|
class ConfigFormatter
|
9
|
-
EXTENSION_ROOT_DEPARTMENT = %r{^
|
10
|
-
SUBDEPARTMENTS = [].freeze
|
11
|
-
AMENDMENTS = %(Metrics/BlockLength)
|
9
|
+
EXTENSION_ROOT_DEPARTMENT = %r{^RSpec/}.freeze
|
12
10
|
COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/'
|
13
11
|
|
14
12
|
def initialize(config, descriptions)
|
@@ -18,18 +16,15 @@ module RuboCop
|
|
18
16
|
|
19
17
|
def dump
|
20
18
|
YAML.dump(unified_config)
|
21
|
-
.gsub(
|
22
|
-
.gsub(
|
23
|
-
.gsub(
|
24
|
-
.gsub('"~"', '~')
|
19
|
+
.gsub(%r{^\w+/}, "\n\\0") # Add an extra newline before each cop.
|
20
|
+
.gsub(/^(\s+)- /, '\1 - ') # Add 2 spaces before each array element.
|
21
|
+
.gsub('"~"', '~') # Don't quote tilde, YAML's null value.
|
25
22
|
end
|
26
23
|
|
27
24
|
private
|
28
25
|
|
29
26
|
def unified_config
|
30
27
|
cops.each_with_object(config.dup) do |cop, unified|
|
31
|
-
next if SUBDEPARTMENTS.include?(cop) || AMENDMENTS.include?(cop)
|
32
|
-
|
33
28
|
replace_nil(unified[cop])
|
34
29
|
unified[cop].merge!(descriptions.fetch(cop))
|
35
30
|
unified[cop]['Reference'] = reference(cop)
|
data/lib/rubocop/rspec/hook.rb
CHANGED
@@ -26,7 +26,7 @@ module RuboCop
|
|
26
26
|
|
27
27
|
# @!method example_group?(node)
|
28
28
|
def_node_matcher :example_group?, <<~PATTERN
|
29
|
-
(
|
29
|
+
(any_block (send #rspec? #ExampleGroups.all ...) ...)
|
30
30
|
PATTERN
|
31
31
|
|
32
32
|
# @!method shared_group?(node)
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
|
36
36
|
# @!method spec_group?(node)
|
37
37
|
def_node_matcher :spec_group?, <<~PATTERN
|
38
|
-
(
|
38
|
+
(any_block (send #rspec?
|
39
39
|
{#SharedGroups.all #ExampleGroups.all}
|
40
40
|
...) ...)
|
41
41
|
PATTERN
|
@@ -50,10 +50,7 @@ module RuboCop
|
|
50
50
|
|
51
51
|
# @!method hook?(node)
|
52
52
|
def_node_matcher :hook?, <<~PATTERN
|
53
|
-
|
54
|
-
(numblock (send nil? #Hooks.all ...) ...)
|
55
|
-
(block (send nil? #Hooks.all ...) ...)
|
56
|
-
}
|
53
|
+
(any_block (send nil? #Hooks.all ...) ...)
|
57
54
|
PATTERN
|
58
55
|
|
59
56
|
# @!method let?(node)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lint_roller'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module RSpec
|
7
|
+
# A plugin that integrates RuboCop RSpec with RuboCop's plugin system.
|
8
|
+
class Plugin < LintRoller::Plugin
|
9
|
+
# :nocov:
|
10
|
+
def about
|
11
|
+
LintRoller::About.new(
|
12
|
+
name: 'rubocop-rspec',
|
13
|
+
version: Version::STRING,
|
14
|
+
homepage: 'https://github.com/rubocop/rubocop-rspec',
|
15
|
+
description: 'Code style checking for RSpec files.'
|
16
|
+
)
|
17
|
+
end
|
18
|
+
# :nocov:
|
19
|
+
|
20
|
+
def supported?(context)
|
21
|
+
context.engine == :rubocop
|
22
|
+
end
|
23
|
+
|
24
|
+
def rules(_context)
|
25
|
+
project_root = Pathname.new(__dir__).join('../../..')
|
26
|
+
|
27
|
+
ConfigObsoletion.files << project_root.join('config', 'obsoletion.yml')
|
28
|
+
|
29
|
+
LintRoller::Rules.new(
|
30
|
+
type: :path,
|
31
|
+
config_format: :rubocop,
|
32
|
+
value: project_root.join('config/default.yml')
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -17,7 +17,6 @@ module RuboCop
|
|
17
17
|
@replacements = replace
|
18
18
|
end
|
19
19
|
|
20
|
-
# rubocop:disable Metrics/MethodLength
|
21
20
|
def rewrite
|
22
21
|
case text
|
23
22
|
when SHOULDNT_BE_PREFIX
|
@@ -32,7 +31,6 @@ module RuboCop
|
|
32
31
|
remove_should_and_pluralize
|
33
32
|
end
|
34
33
|
end
|
35
|
-
# rubocop:enable Metrics/MethodLength
|
36
34
|
|
37
35
|
private
|
38
36
|
|
data/lib/rubocop/rspec.rb
CHANGED
@@ -3,12 +3,5 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# RuboCop RSpec project namespace
|
5
5
|
module RSpec
|
6
|
-
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
7
|
-
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
|
8
|
-
|
9
|
-
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
10
|
-
|
11
|
-
::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config',
|
12
|
-
'obsoletion.yml')
|
13
6
|
end
|
14
7
|
end
|
data/lib/rubocop-rspec.rb
CHANGED
@@ -6,9 +6,9 @@ require 'yaml'
|
|
6
6
|
require 'rubocop'
|
7
7
|
|
8
8
|
require_relative 'rubocop/rspec'
|
9
|
-
require_relative 'rubocop/rspec/inject'
|
10
9
|
require_relative 'rubocop/rspec/language'
|
11
10
|
require_relative 'rubocop/rspec/node'
|
11
|
+
require_relative 'rubocop/rspec/plugin'
|
12
12
|
require_relative 'rubocop/rspec/version'
|
13
13
|
require_relative 'rubocop/rspec/wording'
|
14
14
|
|
@@ -34,8 +34,6 @@ require_relative 'rubocop/rspec/example'
|
|
34
34
|
require_relative 'rubocop/rspec/example_group'
|
35
35
|
require_relative 'rubocop/rspec/hook'
|
36
36
|
|
37
|
-
RuboCop::RSpec::Inject.defaults!
|
38
|
-
|
39
37
|
require_relative 'rubocop/cop/rspec_cops'
|
40
38
|
|
41
39
|
# We have to register our autocorrect incompatibilities in RuboCop's cops
|
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: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Backus
|
@@ -9,22 +9,42 @@ authors:
|
|
9
9
|
- Nils Gemeinhardt
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: lint_roller
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.1'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.1'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: rubocop
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
17
31
|
requirements:
|
18
32
|
- - "~>"
|
19
33
|
- !ruby/object:Gem::Version
|
20
|
-
version: '1.
|
34
|
+
version: '1.72'
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.72.1
|
21
38
|
type: :runtime
|
22
39
|
prerelease: false
|
23
40
|
version_requirements: !ruby/object:Gem::Requirement
|
24
41
|
requirements:
|
25
42
|
- - "~>"
|
26
43
|
- !ruby/object:Gem::Version
|
27
|
-
version: '1.
|
44
|
+
version: '1.72'
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.72.1
|
28
48
|
description: |
|
29
49
|
Code style checking for RSpec files.
|
30
50
|
A plugin for the RuboCop code style enforcing & linting tool.
|
@@ -94,6 +114,7 @@ files:
|
|
94
114
|
- lib/rubocop/cop/rspec/implicit_block_expectation.rb
|
95
115
|
- lib/rubocop/cop/rspec/implicit_expect.rb
|
96
116
|
- lib/rubocop/cop/rspec/implicit_subject.rb
|
117
|
+
- lib/rubocop/cop/rspec/include_examples.rb
|
97
118
|
- lib/rubocop/cop/rspec/indexed_let.rb
|
98
119
|
- lib/rubocop/cop/rspec/instance_spy.rb
|
99
120
|
- lib/rubocop/cop/rspec/instance_variable.rb
|
@@ -178,9 +199,9 @@ files:
|
|
178
199
|
- lib/rubocop/rspec/example.rb
|
179
200
|
- lib/rubocop/rspec/example_group.rb
|
180
201
|
- lib/rubocop/rspec/hook.rb
|
181
|
-
- lib/rubocop/rspec/inject.rb
|
182
202
|
- lib/rubocop/rspec/language.rb
|
183
203
|
- lib/rubocop/rspec/node.rb
|
204
|
+
- lib/rubocop/rspec/plugin.rb
|
184
205
|
- lib/rubocop/rspec/shared_contexts/default_rspec_language_config_context.rb
|
185
206
|
- lib/rubocop/rspec/version.rb
|
186
207
|
- lib/rubocop/rspec/wording.rb
|
@@ -191,6 +212,7 @@ metadata:
|
|
191
212
|
changelog_uri: https://github.com/rubocop/rubocop-rspec/blob/master/CHANGELOG.md
|
192
213
|
documentation_uri: https://docs.rubocop.org/rubocop-rspec/
|
193
214
|
rubygems_mfa_required: 'true'
|
215
|
+
default_lint_roller_plugin: RuboCop::RSpec::Plugin
|
194
216
|
rdoc_options: []
|
195
217
|
require_paths:
|
196
218
|
- lib
|
@@ -205,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
205
227
|
- !ruby/object:Gem::Version
|
206
228
|
version: '0'
|
207
229
|
requirements: []
|
208
|
-
rubygems_version: 3.6.
|
230
|
+
rubygems_version: 3.6.7
|
209
231
|
specification_version: 4
|
210
232
|
summary: Code style checking for RSpec files
|
211
233
|
test_files: []
|
data/lib/rubocop/rspec/inject.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module RSpec
|
5
|
-
# Because RuboCop doesn't yet support plugins, we have to monkey patch in a
|
6
|
-
# bit of our configuration.
|
7
|
-
module Inject
|
8
|
-
def self.defaults!
|
9
|
-
path = CONFIG_DEFAULT.to_s
|
10
|
-
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
11
|
-
config = RuboCop::Config.new(hash, path)
|
12
|
-
puts "configuration from #{path}" if ConfigLoader.debug?
|
13
|
-
config = ConfigLoader.merge_with_default(config, path)
|
14
|
-
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|