rubocop-rspec 1.37.1 → 1.41.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 +53 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/README.md +2 -62
- data/config/default.yml +155 -15
- data/lib/rubocop-rspec.rb +3 -1
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +69 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +5 -1
- data/lib/rubocop/cop/rspec/cop.rb +9 -29
- data/lib/rubocop/cop/rspec/describe_class.rb +20 -5
- data/lib/rubocop/cop/rspec/describe_method.rb +0 -1
- data/lib/rubocop/cop/rspec/empty_hook.rb +50 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +27 -2
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +5 -2
- data/lib/rubocop/cop/rspec/file_path.rb +32 -4
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +3 -21
- data/lib/rubocop/cop/rspec/instance_variable.rb +16 -11
- data/lib/rubocop/cop/rspec/leading_subject.rb +3 -10
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -4
- data/lib/rubocop/cop/rspec/let_before_examples.rb +3 -21
- data/lib/rubocop/cop/rspec/let_setup.rb +15 -3
- data/lib/rubocop/cop/rspec/named_subject.rb +6 -6
- data/lib/rubocop/cop/rspec/nested_groups.rb +9 -10
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +2 -2
- data/lib/rubocop/cop/rspec/rails/http_status.rb +2 -0
- data/lib/rubocop/cop/rspec/repeated_description.rb +17 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +97 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +96 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +3 -2
- data/lib/rubocop/cop/rspec/scattered_let.rb +13 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +27 -9
- data/lib/rubocop/cop/rspec/shared_examples.rb +1 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +23 -51
- data/lib/rubocop/cop/rspec/variable_definition.rb +56 -0
- data/lib/rubocop/cop/rspec/variable_name.rb +47 -0
- data/lib/rubocop/cop/rspec_cops.rb +7 -1
- data/lib/rubocop/rspec/corrector/move_node.rb +52 -0
- data/lib/rubocop/rspec/description_extractor.rb +2 -6
- data/lib/rubocop/rspec/example.rb +1 -1
- data/lib/rubocop/rspec/example_group.rb +21 -49
- data/lib/rubocop/rspec/factory_bot.rb +7 -1
- data/lib/rubocop/rspec/hook.rb +44 -11
- data/lib/rubocop/rspec/language.rb +20 -0
- data/lib/rubocop/rspec/language/node_pattern.rb +5 -1
- data/lib/rubocop/rspec/top_level_group.rb +44 -0
- data/lib/rubocop/rspec/variable.rb +16 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +20 -11
- data/lib/rubocop/rspec/util.rb +0 -19
@@ -14,72 +14,44 @@ module RuboCop
|
|
14
14
|
ExampleGroups::ALL + SharedGroups::ALL + Includes::ALL
|
15
15
|
).block_pattern
|
16
16
|
|
17
|
+
def lets
|
18
|
+
find_all_in_scope(node, :let?)
|
19
|
+
end
|
20
|
+
|
17
21
|
def subjects
|
18
|
-
|
22
|
+
find_all_in_scope(node, :subject?)
|
19
23
|
end
|
20
24
|
|
21
25
|
def examples
|
22
|
-
|
26
|
+
find_all_in_scope(node, :example?).map(&Example.public_method(:new))
|
23
27
|
end
|
24
28
|
|
25
29
|
def hooks
|
26
|
-
|
30
|
+
find_all_in_scope(node, :hook?).map(&Hook.public_method(:new))
|
27
31
|
end
|
28
32
|
|
29
33
|
private
|
30
34
|
|
31
|
-
|
32
|
-
node.each_child_node.flat_map do |child|
|
33
|
-
find_subjects(child)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def find_subjects(node)
|
38
|
-
return [] if scope_change?(node)
|
39
|
-
|
40
|
-
if subject?(node)
|
41
|
-
[node]
|
42
|
-
else
|
43
|
-
subjects_in_scope(node)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def hooks_in_scope(node)
|
48
|
-
node.each_child_node.flat_map do |child|
|
49
|
-
find_hooks(child)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def find_hooks(node)
|
54
|
-
return [] if scope_change?(node) || example?(node)
|
55
|
-
|
56
|
-
if hook?(node)
|
57
|
-
[node]
|
58
|
-
else
|
59
|
-
hooks_in_scope(node)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def examples_in_scope(node, &blk)
|
64
|
-
node.each_child_node.flat_map do |child|
|
65
|
-
find_examples(child, &blk)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Recursively search for examples within the current scope
|
35
|
+
# Recursively search for predicate within the current scope
|
70
36
|
#
|
71
|
-
# Searches node
|
37
|
+
# Searches node and halts when a scope change is detected
|
72
38
|
#
|
73
|
-
# @param node [RuboCop::Node] node to recursively search
|
39
|
+
# @param node [RuboCop::Node] node to recursively search
|
74
40
|
#
|
75
|
-
# @return [Array<RuboCop::Node>] discovered
|
76
|
-
def
|
77
|
-
|
41
|
+
# @return [Array<RuboCop::Node>] discovered nodes
|
42
|
+
def find_all_in_scope(node, predicate)
|
43
|
+
node.each_child_node.flat_map do |child|
|
44
|
+
find_all(child, predicate)
|
45
|
+
end
|
46
|
+
end
|
78
47
|
|
79
|
-
|
48
|
+
def find_all(node, predicate)
|
49
|
+
if public_send(predicate, node)
|
80
50
|
[node]
|
51
|
+
elsif scope_change?(node) || example?(node)
|
52
|
+
[]
|
81
53
|
else
|
82
|
-
|
54
|
+
find_all_in_scope(node, predicate)
|
83
55
|
end
|
84
56
|
end
|
85
57
|
end
|
@@ -4,7 +4,13 @@ module RuboCop
|
|
4
4
|
module RSpec
|
5
5
|
# RuboCop FactoryBot project namespace
|
6
6
|
module FactoryBot
|
7
|
-
ATTRIBUTE_DEFINING_METHODS = %i[
|
7
|
+
ATTRIBUTE_DEFINING_METHODS = %i[
|
8
|
+
factory
|
9
|
+
ignore
|
10
|
+
trait
|
11
|
+
traits_for_enum
|
12
|
+
transient
|
13
|
+
].freeze
|
8
14
|
|
9
15
|
UNPROXIED_METHODS = %i[
|
10
16
|
__send__
|
data/lib/rubocop/rspec/hook.rb
CHANGED
@@ -4,21 +4,24 @@ module RuboCop
|
|
4
4
|
module RSpec
|
5
5
|
# Wrapper for RSpec hook
|
6
6
|
class Hook < Concept
|
7
|
-
|
8
|
-
|
7
|
+
def_node_matcher :extract_metadata, <<~PATTERN
|
8
|
+
(block
|
9
|
+
{
|
10
|
+
(send _ _ #valid_scope? $...)
|
11
|
+
(send _ _ $...)
|
12
|
+
}
|
13
|
+
...
|
14
|
+
)
|
15
|
+
PATTERN
|
9
16
|
|
10
17
|
def name
|
11
18
|
node.method_name
|
12
19
|
end
|
13
20
|
|
14
21
|
def knowable_scope?
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
def valid_scope?
|
21
|
-
STANDARDIZED_SCOPES.include?(scope)
|
22
|
+
scope_argument.nil? ||
|
23
|
+
scope_argument.sym_type? ||
|
24
|
+
scope_argument.hash_type?
|
22
25
|
end
|
23
26
|
|
24
27
|
def example?
|
@@ -26,17 +29,47 @@ module RuboCop
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def scope
|
32
|
+
return :each if scope_argument&.hash_type?
|
33
|
+
|
29
34
|
case scope_name
|
30
35
|
when nil, :each, :example then :each
|
31
36
|
when :context, :all then :context
|
32
37
|
when :suite then :suite
|
33
|
-
else
|
34
|
-
scope_name
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
41
|
+
def metadata
|
42
|
+
(extract_metadata(node) || [])
|
43
|
+
.map { |meta| transform_metadata(meta) }
|
44
|
+
.flatten
|
45
|
+
.inject(&:merge)
|
46
|
+
end
|
47
|
+
|
38
48
|
private
|
39
49
|
|
50
|
+
def valid_scope?(node)
|
51
|
+
node&.sym_type? && Hooks::Scopes::ALL.include?(node.value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def transform_metadata(meta)
|
55
|
+
if meta.sym_type?
|
56
|
+
{ meta => true }
|
57
|
+
else
|
58
|
+
# This check is to be able to compare those two hooks:
|
59
|
+
#
|
60
|
+
# before(:example, :special) { ... }
|
61
|
+
# before(:example, special: true) { ... }
|
62
|
+
#
|
63
|
+
# In the second case it's a node with a pair that has a value
|
64
|
+
# of a `true_type?`.
|
65
|
+
meta.pairs.map { |pair| { pair.key => transform_true(pair.value) } }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def transform_true(node)
|
70
|
+
node.true_type? ? true : node
|
71
|
+
end
|
72
|
+
|
40
73
|
def scope_name
|
41
74
|
scope_argument.to_a.first
|
42
75
|
end
|
@@ -28,6 +28,14 @@ module RuboCop
|
|
28
28
|
"(block #{send_pattern} ...)"
|
29
29
|
end
|
30
30
|
|
31
|
+
def block_pass_pattern
|
32
|
+
"(send #{RSPEC} #{node_pattern_union} _ block_pass)"
|
33
|
+
end
|
34
|
+
|
35
|
+
def block_or_block_pass_pattern
|
36
|
+
"{#{block_pattern} #{block_pass_pattern}}"
|
37
|
+
end
|
38
|
+
|
31
39
|
def send_pattern
|
32
40
|
"(send #{RSPEC} #{node_pattern_union} ...)"
|
33
41
|
end
|
@@ -94,6 +102,18 @@ module RuboCop
|
|
94
102
|
append_after
|
95
103
|
]
|
96
104
|
)
|
105
|
+
|
106
|
+
module Scopes
|
107
|
+
ALL = SelectorSet.new(
|
108
|
+
%i[
|
109
|
+
each
|
110
|
+
example
|
111
|
+
context
|
112
|
+
all
|
113
|
+
suite
|
114
|
+
]
|
115
|
+
)
|
116
|
+
end
|
97
117
|
end
|
98
118
|
|
99
119
|
module Helpers
|
@@ -8,6 +8,10 @@ module RuboCop
|
|
8
8
|
extend RuboCop::NodePattern::Macros
|
9
9
|
|
10
10
|
def_node_matcher :example_group?, ExampleGroups::ALL.block_pattern
|
11
|
+
def_node_matcher :shared_group?, SharedGroups::ALL.block_pattern
|
12
|
+
|
13
|
+
spec_groups = ExampleGroups::ALL + SharedGroups::ALL
|
14
|
+
def_node_matcher :spec_group?, spec_groups.block_pattern
|
11
15
|
|
12
16
|
def_node_matcher :example_group_with_body?, <<-PATTERN
|
13
17
|
(block #{ExampleGroups::ALL.send_pattern} args [!nil?])
|
@@ -17,7 +21,7 @@ module RuboCop
|
|
17
21
|
|
18
22
|
def_node_matcher :hook?, Hooks::ALL.block_pattern
|
19
23
|
|
20
|
-
def_node_matcher :let?, Helpers::ALL.
|
24
|
+
def_node_matcher :let?, Helpers::ALL.block_or_block_pass_pattern
|
21
25
|
|
22
26
|
def_node_matcher :subject?, Subject::ALL.block_pattern
|
23
27
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Helper methods for top level example group cops
|
6
|
+
module TopLevelGroup
|
7
|
+
extend RuboCop::NodePattern::Macros
|
8
|
+
include RuboCop::RSpec::Language
|
9
|
+
|
10
|
+
def_node_matcher :example_or_shared_group?,
|
11
|
+
(ExampleGroups::ALL + SharedGroups::ALL).block_pattern
|
12
|
+
|
13
|
+
def on_block(node)
|
14
|
+
return unless respond_to?(:on_top_level_group)
|
15
|
+
return unless top_level_group?(node)
|
16
|
+
|
17
|
+
on_top_level_group(node)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def top_level_group?(node)
|
23
|
+
top_level_groups.include?(node)
|
24
|
+
end
|
25
|
+
|
26
|
+
def top_level_groups
|
27
|
+
@top_level_groups ||=
|
28
|
+
top_level_nodes.select { |n| example_or_shared_group?(n) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def top_level_nodes
|
32
|
+
if root_node.begin_type?
|
33
|
+
root_node.children
|
34
|
+
else
|
35
|
+
[root_node]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def root_node
|
40
|
+
processed_source.ast
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
# Helps check offenses with variable definitions
|
6
|
+
module Variable
|
7
|
+
include Language
|
8
|
+
extend RuboCop::NodePattern::Macros
|
9
|
+
|
10
|
+
def_node_matcher :variable_definition?, <<~PATTERN
|
11
|
+
(send #{RSPEC} #{(Helpers::ALL + Subject::ALL).node_pattern_union}
|
12
|
+
$({sym str dsym dstr} ...) ...)
|
13
|
+
PATTERN
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.41.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Backus
|
8
8
|
- Ian MacLeod
|
9
9
|
- Nils Gemeinhardt
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2020-07-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -72,16 +72,16 @@ dependencies:
|
|
72
72
|
name: simplecov
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
|
-
- - "
|
75
|
+
- - "<"
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: '0'
|
77
|
+
version: '0.18'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
|
-
- - "
|
82
|
+
- - "<"
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: '0'
|
84
|
+
version: '0.18'
|
85
85
|
- !ruby/object:Gem::Dependency
|
86
86
|
name: yard
|
87
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,6 +110,7 @@ extra_rdoc_files:
|
|
110
110
|
- README.md
|
111
111
|
files:
|
112
112
|
- CHANGELOG.md
|
113
|
+
- CODE_OF_CONDUCT.md
|
113
114
|
- MIT-LICENSE.md
|
114
115
|
- README.md
|
115
116
|
- config/default.yml
|
@@ -123,6 +124,7 @@ files:
|
|
123
124
|
- lib/rubocop/cop/rspec/before_after_all.rb
|
124
125
|
- lib/rubocop/cop/rspec/capybara/current_path_expectation.rb
|
125
126
|
- lib/rubocop/cop/rspec/capybara/feature_methods.rb
|
127
|
+
- lib/rubocop/cop/rspec/capybara/visibility_matcher.rb
|
126
128
|
- lib/rubocop/cop/rspec/context_method.rb
|
127
129
|
- lib/rubocop/cop/rspec/context_wording.rb
|
128
130
|
- lib/rubocop/cop/rspec/cop.rb
|
@@ -133,6 +135,7 @@ files:
|
|
133
135
|
- lib/rubocop/cop/rspec/described_class_module_wrapping.rb
|
134
136
|
- lib/rubocop/cop/rspec/dialect.rb
|
135
137
|
- lib/rubocop/cop/rspec/empty_example_group.rb
|
138
|
+
- lib/rubocop/cop/rspec/empty_hook.rb
|
136
139
|
- lib/rubocop/cop/rspec/empty_line_after_example.rb
|
137
140
|
- lib/rubocop/cop/rspec/empty_line_after_example_group.rb
|
138
141
|
- lib/rubocop/cop/rspec/empty_line_after_final_let.rb
|
@@ -182,6 +185,8 @@ files:
|
|
182
185
|
- lib/rubocop/cop/rspec/receive_never.rb
|
183
186
|
- lib/rubocop/cop/rspec/repeated_description.rb
|
184
187
|
- lib/rubocop/cop/rspec/repeated_example.rb
|
188
|
+
- lib/rubocop/cop/rspec/repeated_example_group_body.rb
|
189
|
+
- lib/rubocop/cop/rspec/repeated_example_group_description.rb
|
185
190
|
- lib/rubocop/cop/rspec/return_from_stub.rb
|
186
191
|
- lib/rubocop/cop/rspec/scattered_let.rb
|
187
192
|
- lib/rubocop/cop/rspec/scattered_setup.rb
|
@@ -190,6 +195,8 @@ files:
|
|
190
195
|
- lib/rubocop/cop/rspec/single_argument_message_chain.rb
|
191
196
|
- lib/rubocop/cop/rspec/subject_stub.rb
|
192
197
|
- lib/rubocop/cop/rspec/unspecified_exception.rb
|
198
|
+
- lib/rubocop/cop/rspec/variable_definition.rb
|
199
|
+
- lib/rubocop/cop/rspec/variable_name.rb
|
193
200
|
- lib/rubocop/cop/rspec/verified_doubles.rb
|
194
201
|
- lib/rubocop/cop/rspec/void_expect.rb
|
195
202
|
- lib/rubocop/cop/rspec/yield.rb
|
@@ -199,6 +206,7 @@ files:
|
|
199
206
|
- lib/rubocop/rspec/blank_line_separation.rb
|
200
207
|
- lib/rubocop/rspec/concept.rb
|
201
208
|
- lib/rubocop/rspec/config_formatter.rb
|
209
|
+
- lib/rubocop/rspec/corrector/move_node.rb
|
202
210
|
- lib/rubocop/rspec/description_extractor.rb
|
203
211
|
- lib/rubocop/rspec/example.rb
|
204
212
|
- lib/rubocop/rspec/example_group.rb
|
@@ -210,7 +218,8 @@ files:
|
|
210
218
|
- lib/rubocop/rspec/language/node_pattern.rb
|
211
219
|
- lib/rubocop/rspec/node.rb
|
212
220
|
- lib/rubocop/rspec/top_level_describe.rb
|
213
|
-
- lib/rubocop/rspec/
|
221
|
+
- lib/rubocop/rspec/top_level_group.rb
|
222
|
+
- lib/rubocop/rspec/variable.rb
|
214
223
|
- lib/rubocop/rspec/version.rb
|
215
224
|
- lib/rubocop/rspec/wording.rb
|
216
225
|
homepage: https://github.com/rubocop-hq/rubocop-rspec
|
@@ -219,7 +228,7 @@ licenses:
|
|
219
228
|
metadata:
|
220
229
|
changelog_uri: https://github.com/rubocop-hq/rubocop-rspec/blob/master/CHANGELOG.md
|
221
230
|
documentation_uri: https://rubocop-rspec.readthedocs.io/
|
222
|
-
post_install_message:
|
231
|
+
post_install_message:
|
223
232
|
rdoc_options: []
|
224
233
|
require_paths:
|
225
234
|
- lib
|
@@ -227,7 +236,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
227
236
|
requirements:
|
228
237
|
- - ">="
|
229
238
|
- !ruby/object:Gem::Version
|
230
|
-
version: 2.
|
239
|
+
version: 2.4.0
|
231
240
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
232
241
|
requirements:
|
233
242
|
- - ">="
|
@@ -235,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
235
244
|
version: '0'
|
236
245
|
requirements: []
|
237
246
|
rubygems_version: 3.0.3
|
238
|
-
signing_key:
|
247
|
+
signing_key:
|
239
248
|
specification_version: 4
|
240
249
|
summary: Code style checking for RSpec files
|
241
250
|
test_files: []
|
data/lib/rubocop/rspec/util.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module RSpec
|
5
|
-
# Utility methods
|
6
|
-
module Util
|
7
|
-
# Error raised by `Util.one` if size is less than zero or greater than one
|
8
|
-
SizeError = Class.new(IndexError)
|
9
|
-
|
10
|
-
# Return only element in array if it contains exactly one member
|
11
|
-
def one(array)
|
12
|
-
return array.first if array.one?
|
13
|
-
|
14
|
-
raise SizeError,
|
15
|
-
"expected size to be exactly 1 but size was #{array.size}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|