rubocop-rspec 1.21.0 → 1.22.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 +10 -0
- data/Rakefile +19 -0
- data/config/default.yml +19 -0
- data/lib/rubocop-rspec.rb +17 -72
- data/lib/rubocop/cop/rspec/context_wording.rb +2 -2
- data/lib/rubocop/cop/rspec/describe_class.rb +1 -1
- data/lib/rubocop/cop/rspec/describe_symbol.rb +1 -1
- data/lib/rubocop/cop/rspec/described_class.rb +2 -4
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +6 -10
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +4 -4
- data/lib/rubocop/cop/rspec/example_without_description.rb +89 -0
- data/lib/rubocop/cop/rspec/expect_change.rb +102 -0
- data/lib/rubocop/cop/rspec/hook_argument.rb +9 -9
- data/lib/rubocop/cop/rspec/instance_variable.rb +9 -0
- data/lib/rubocop/cop/rspec/leading_subject.rb +1 -8
- data/lib/rubocop/cop/rspec/let_before_examples.rb +46 -6
- data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -2
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +2 -4
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +1 -2
- data/lib/rubocop/cop/rspec/nested_groups.rb +2 -2
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +11 -13
- data/lib/rubocop/cop/rspec/return_from_stub.rb +85 -0
- data/lib/rubocop/cop/rspec/scattered_let.rb +9 -13
- data/lib/rubocop/cop/rspec/shared_context.rb +2 -2
- data/lib/rubocop/cop/rspec_cops.rb +59 -0
- data/lib/rubocop/rspec/description_extractor.rb +13 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +1 -1
- data/spec/rubocop/cop/rspec/describe_class_spec.rb +7 -0
- data/spec/rubocop/cop/rspec/example_without_description_spec.rb +82 -0
- data/spec/rubocop/cop/rspec/expect_change_spec.rb +78 -0
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +18 -0
- data/spec/rubocop/cop/rspec/let_before_examples_spec.rb +48 -0
- data/spec/rubocop/cop/rspec/return_from_stub_spec.rb +65 -0
- data/spec/rubocop/rspec/description_extractor_spec.rb +6 -2
- metadata +11 -4
@@ -13,49 +13,49 @@ module RuboCop
|
|
13
13
|
# @example when configuration is `EnforcedStyle: implicit`
|
14
14
|
# # bad
|
15
15
|
# before(:each) do
|
16
|
-
# ...
|
16
|
+
# # ...
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
# # bad
|
20
20
|
# before(:example) do
|
21
|
-
# ...
|
21
|
+
# # ...
|
22
22
|
# end
|
23
23
|
#
|
24
24
|
# # good
|
25
25
|
# before do
|
26
|
-
# ...
|
26
|
+
# # ...
|
27
27
|
# end
|
28
28
|
#
|
29
29
|
# @example when configuration is `EnforcedStyle: each`
|
30
30
|
# # bad
|
31
31
|
# before(:example) do
|
32
|
-
# ...
|
32
|
+
# # ...
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
# # good
|
36
36
|
# before do
|
37
|
-
# ...
|
37
|
+
# # ...
|
38
38
|
# end
|
39
39
|
#
|
40
40
|
# # good
|
41
41
|
# before(:each) do
|
42
|
-
# ...
|
42
|
+
# # ...
|
43
43
|
# end
|
44
44
|
#
|
45
45
|
# @example when configuration is `EnforcedStyle: example`
|
46
46
|
# # bad
|
47
47
|
# before(:each) do
|
48
|
-
# ...
|
48
|
+
# # ...
|
49
49
|
# end
|
50
50
|
#
|
51
51
|
# # bad
|
52
52
|
# before do
|
53
|
-
# ...
|
53
|
+
# # ...
|
54
54
|
# end
|
55
55
|
#
|
56
56
|
# # good
|
57
57
|
# before(:example) do
|
58
|
-
# ...
|
58
|
+
# # ...
|
59
59
|
# end
|
60
60
|
class HookArgument < Cop
|
61
61
|
include ConfigurableEnforcedStyle
|
@@ -53,6 +53,10 @@ module RuboCop
|
|
53
53
|
|
54
54
|
def_node_matcher :spec_group?, EXAMPLE_GROUP_METHODS.block_pattern
|
55
55
|
|
56
|
+
def_node_matcher :dynamic_class?, <<-PATTERN
|
57
|
+
(block (send (const nil? :Class) :new ...) ...)
|
58
|
+
PATTERN
|
59
|
+
|
56
60
|
def_node_search :ivar_usage, '$(ivar $_)'
|
57
61
|
|
58
62
|
def_node_search :ivar_assigned?, '(ivasgn % ...)'
|
@@ -61,6 +65,7 @@ module RuboCop
|
|
61
65
|
return unless spec_group?(node)
|
62
66
|
|
63
67
|
ivar_usage(node) do |ivar, name|
|
68
|
+
return if inside_dynamic_class?(ivar)
|
64
69
|
return if assignment_only? && !ivar_assigned?(node, name)
|
65
70
|
|
66
71
|
add_offense(ivar, location: :expression)
|
@@ -69,6 +74,10 @@ module RuboCop
|
|
69
74
|
|
70
75
|
private
|
71
76
|
|
77
|
+
def inside_dynamic_class?(node)
|
78
|
+
node.each_ancestor(:block).any? { |block| dynamic_class?(block) }
|
79
|
+
end
|
80
|
+
|
72
81
|
def assignment_only?
|
73
82
|
cop_config['AssignmentOnly']
|
74
83
|
end
|
@@ -62,14 +62,7 @@ module RuboCop
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def node_range(node)
|
65
|
-
|
66
|
-
range = range_with_surrounding_space(
|
67
|
-
range: range, side: :left, newlines: false
|
68
|
-
)
|
69
|
-
range = range_with_surrounding_space(
|
70
|
-
range: range, side: :right, newlines: true
|
71
|
-
)
|
72
|
-
range
|
65
|
+
range_by_whole_lines(node.source_range, include_final_newline: true)
|
73
66
|
end
|
74
67
|
|
75
68
|
def in_spec_block?(node)
|
@@ -47,6 +47,17 @@ module RuboCop
|
|
47
47
|
check_let_declarations(node.body) if multiline_block?(node.body)
|
48
48
|
end
|
49
49
|
|
50
|
+
def autocorrect(node)
|
51
|
+
lambda do |corrector|
|
52
|
+
first_example = find_first_example(node.parent)
|
53
|
+
first_example_pos = first_example.loc.expression
|
54
|
+
indent = "\n" + ' ' * first_example.loc.column
|
55
|
+
|
56
|
+
corrector.insert_before(first_example_pos, source(node) + indent)
|
57
|
+
corrector.remove(node_range_with_surrounding_space(node))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
50
61
|
private
|
51
62
|
|
52
63
|
def multiline_block?(block)
|
@@ -54,16 +65,45 @@ module RuboCop
|
|
54
65
|
end
|
55
66
|
|
56
67
|
def check_let_declarations(node)
|
57
|
-
|
68
|
+
first_example = find_first_example(node)
|
69
|
+
return unless first_example
|
58
70
|
|
59
71
|
node.each_child_node do |child|
|
60
|
-
if
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
next if child.sibling_index < first_example.sibling_index
|
73
|
+
add_offense(child, location: :expression) if let?(child)
|
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(node.loc.expression.begin_pos, last_node_loc(node))
|
92
|
+
end
|
93
|
+
|
94
|
+
def last_node_loc(node)
|
95
|
+
heredoc = heredoc_lines(node).last
|
96
|
+
|
97
|
+
if heredoc
|
98
|
+
heredoc.loc.heredoc_end.end_pos
|
99
|
+
else
|
100
|
+
node.loc.end.end_pos
|
65
101
|
end
|
66
102
|
end
|
103
|
+
|
104
|
+
def heredoc_lines(node)
|
105
|
+
node.body.child_nodes.select { |n| n.loc.respond_to?(:heredoc_end) }
|
106
|
+
end
|
67
107
|
end
|
68
108
|
end
|
69
109
|
end
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
26
26
|
# expect(user.name).to eq("John")
|
27
27
|
# end
|
28
28
|
#
|
29
|
-
# it 'sets the users age'
|
29
|
+
# it 'sets the users age' do
|
30
30
|
# expect(user.age).to eq(22)
|
31
31
|
# end
|
32
32
|
# end
|
@@ -96,10 +96,8 @@ module RuboCop
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def flag_example(node, expectation_count:)
|
99
|
-
method, = *node
|
100
|
-
|
101
99
|
add_offense(
|
102
|
-
|
100
|
+
node.send_node,
|
103
101
|
location: :expression,
|
104
102
|
message: format(
|
105
103
|
MSG,
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
21
21
|
# let(:user_attributes) do
|
22
22
|
# {
|
23
23
|
# name: 'John',
|
24
|
-
# age: 22
|
24
|
+
# age: 22,
|
25
25
|
# role: role
|
26
26
|
# }
|
27
27
|
# end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
# let(:user) do
|
44
44
|
# UserCreate.call(
|
45
45
|
# name: 'John',
|
46
|
-
# age: 22
|
46
|
+
# age: 22,
|
47
47
|
# role: 'admin'
|
48
48
|
# )
|
49
49
|
# end
|
@@ -7,20 +7,20 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# let(:foo) { bar }
|
11
|
+
# let(:foo) { baz }
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
13
|
+
# subject(:foo) { bar }
|
14
|
+
# let(:foo) { baz }
|
15
15
|
#
|
16
|
-
#
|
17
|
-
#
|
16
|
+
# let(:foo) { bar }
|
17
|
+
# let!(:foo) { baz }
|
18
18
|
#
|
19
19
|
# # good
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
20
|
+
# subject(:test) { something }
|
21
|
+
# let(:foo) { bar }
|
22
|
+
# let(:baz) { baz }
|
23
|
+
# let!(:other) { other }
|
24
24
|
class OverwritingSetup < Cop
|
25
25
|
MSG = '`%<name>s` is already defined.'.freeze
|
26
26
|
|
@@ -31,9 +31,7 @@ module RuboCop
|
|
31
31
|
def on_block(node)
|
32
32
|
return unless example_group_with_body?(node)
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
find_duplicates(body) do |duplicate, name|
|
34
|
+
find_duplicates(node.body) do |duplicate, name|
|
37
35
|
add_offense(
|
38
36
|
duplicate,
|
39
37
|
location: :expression,
|
@@ -53,6 +53,14 @@ module RuboCop
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
def autocorrect(node)
|
57
|
+
if style == :block
|
58
|
+
AndReturnCallCorrector.new(node)
|
59
|
+
else
|
60
|
+
BlockBodyCorrector.new(node)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
56
64
|
private
|
57
65
|
|
58
66
|
def check_and_return_call(node)
|
@@ -84,6 +92,83 @@ module RuboCop
|
|
84
92
|
def dynamic?(node)
|
85
93
|
!node.recursive_literal?
|
86
94
|
end
|
95
|
+
|
96
|
+
# :nodoc:
|
97
|
+
class AndReturnCallCorrector
|
98
|
+
def initialize(node)
|
99
|
+
@node = node
|
100
|
+
@receiver, _method_name, @args = *node
|
101
|
+
end
|
102
|
+
|
103
|
+
def call(corrector)
|
104
|
+
# Heredoc autocorrection is not yet implemented.
|
105
|
+
return if heredoc?
|
106
|
+
|
107
|
+
corrector.replace(range, " { #{replacement} }")
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
attr_reader :node, :receiver, :args
|
113
|
+
|
114
|
+
def heredoc?
|
115
|
+
args.loc.is_a?(Parser::Source::Map::Heredoc)
|
116
|
+
end
|
117
|
+
|
118
|
+
def range
|
119
|
+
Parser::Source::Range.new(
|
120
|
+
node.source_range.source_buffer,
|
121
|
+
receiver.source_range.end_pos,
|
122
|
+
node.source_range.end_pos
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
def replacement
|
127
|
+
if hash_without_braces?
|
128
|
+
"{ #{args.source} }"
|
129
|
+
else
|
130
|
+
args.source
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def hash_without_braces?
|
135
|
+
args.hash_type? && !args.braces?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# :nodoc:
|
140
|
+
class BlockBodyCorrector
|
141
|
+
def initialize(node)
|
142
|
+
@block = node.each_ancestor(:block).first
|
143
|
+
@node = node
|
144
|
+
@body = block.body || NULL_BLOCK_BODY
|
145
|
+
end
|
146
|
+
|
147
|
+
def call(corrector)
|
148
|
+
# Heredoc autocorrection is not yet implemented.
|
149
|
+
return if heredoc?
|
150
|
+
|
151
|
+
corrector.replace(range, ".and_return(#{body.source})")
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
attr_reader :node, :block, :body
|
157
|
+
|
158
|
+
def range
|
159
|
+
Parser::Source::Range.new(
|
160
|
+
block.source_range.source_buffer,
|
161
|
+
node.source_range.end_pos,
|
162
|
+
block.source_range.end_pos
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
def heredoc?
|
167
|
+
body.loc.is_a?(Parser::Source::Map::Heredoc)
|
168
|
+
end
|
169
|
+
|
170
|
+
NULL_BLOCK_BODY = Struct.new(:loc, :source).new(nil, 'nil')
|
171
|
+
end
|
87
172
|
end
|
88
173
|
end
|
89
174
|
end
|
@@ -34,22 +34,18 @@ module RuboCop
|
|
34
34
|
def on_block(node)
|
35
35
|
return unless example_group_with_body?(node)
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
check_let_declarations(body)
|
37
|
+
check_let_declarations(node.body)
|
40
38
|
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
private
|
41
|
+
|
42
|
+
def check_let_declarations(body)
|
43
|
+
lets = body.each_child_node.select { |node| let?(node) }
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
elsif let_found
|
51
|
-
mix_found = true
|
52
|
-
end
|
45
|
+
first_let = lets.first
|
46
|
+
lets.each_with_index do |node, idx|
|
47
|
+
next if node.sibling_index == first_let.sibling_index + idx
|
48
|
+
add_offense(node, location: :expression)
|
53
49
|
end
|
54
50
|
end
|
55
51
|
end
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
# it 'does x' do
|
15
15
|
# end
|
16
16
|
#
|
17
|
-
# it 'does
|
17
|
+
# it 'does y' do
|
18
18
|
# end
|
19
19
|
# end
|
20
20
|
#
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
# it 'does x' do
|
24
24
|
# end
|
25
25
|
#
|
26
|
-
# it 'does
|
26
|
+
# it 'does y' do
|
27
27
|
# end
|
28
28
|
# end
|
29
29
|
#
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'rspec/capybara/current_path_expectation'
|
2
|
+
require_relative 'rspec/capybara/feature_methods'
|
3
|
+
|
4
|
+
require_relative 'rspec/factory_bot/dynamic_attribute_defined_statically'
|
5
|
+
|
6
|
+
require_relative 'rspec/align_left_let_brace'
|
7
|
+
require_relative 'rspec/align_right_let_brace'
|
8
|
+
require_relative 'rspec/any_instance'
|
9
|
+
require_relative 'rspec/around_block'
|
10
|
+
require_relative 'rspec/be_eql'
|
11
|
+
require_relative 'rspec/before_after_all'
|
12
|
+
require_relative 'rspec/context_wording'
|
13
|
+
require_relative 'rspec/describe_class'
|
14
|
+
require_relative 'rspec/described_class'
|
15
|
+
require_relative 'rspec/describe_method'
|
16
|
+
require_relative 'rspec/describe_symbol'
|
17
|
+
require_relative 'rspec/empty_example_group'
|
18
|
+
require_relative 'rspec/empty_line_after_final_let'
|
19
|
+
require_relative 'rspec/empty_line_after_subject'
|
20
|
+
require_relative 'rspec/example_length'
|
21
|
+
require_relative 'rspec/example_without_description'
|
22
|
+
require_relative 'rspec/example_wording'
|
23
|
+
require_relative 'rspec/expect_actual'
|
24
|
+
require_relative 'rspec/expect_change'
|
25
|
+
require_relative 'rspec/expect_in_hook'
|
26
|
+
require_relative 'rspec/expect_output'
|
27
|
+
require_relative 'rspec/file_path'
|
28
|
+
require_relative 'rspec/focus'
|
29
|
+
require_relative 'rspec/hook_argument'
|
30
|
+
require_relative 'rspec/implicit_expect'
|
31
|
+
require_relative 'rspec/instance_spy'
|
32
|
+
require_relative 'rspec/instance_variable'
|
33
|
+
require_relative 'rspec/invalid_predicate_matcher'
|
34
|
+
require_relative 'rspec/it_behaves_like'
|
35
|
+
require_relative 'rspec/iterated_expectation'
|
36
|
+
require_relative 'rspec/leading_subject'
|
37
|
+
require_relative 'rspec/let_before_examples'
|
38
|
+
require_relative 'rspec/let_setup'
|
39
|
+
require_relative 'rspec/message_chain'
|
40
|
+
require_relative 'rspec/message_expectation'
|
41
|
+
require_relative 'rspec/message_spies'
|
42
|
+
require_relative 'rspec/multiple_describes'
|
43
|
+
require_relative 'rspec/multiple_expectations'
|
44
|
+
require_relative 'rspec/multiple_subjects'
|
45
|
+
require_relative 'rspec/named_subject'
|
46
|
+
require_relative 'rspec/nested_groups'
|
47
|
+
require_relative 'rspec/not_to_not'
|
48
|
+
require_relative 'rspec/overwriting_setup'
|
49
|
+
require_relative 'rspec/predicate_matcher'
|
50
|
+
require_relative 'rspec/repeated_description'
|
51
|
+
require_relative 'rspec/repeated_example'
|
52
|
+
require_relative 'rspec/return_from_stub'
|
53
|
+
require_relative 'rspec/scattered_let'
|
54
|
+
require_relative 'rspec/scattered_setup'
|
55
|
+
require_relative 'rspec/shared_context'
|
56
|
+
require_relative 'rspec/single_argument_message_chain'
|
57
|
+
require_relative 'rspec/subject_stub'
|
58
|
+
require_relative 'rspec/verified_doubles'
|
59
|
+
require_relative 'rspec/void_expect'
|