rubocop-rspec 1.42.0 → 1.44.1
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 +44 -2
- data/config/default.yml +41 -3
- data/lib/rubocop-rspec.rb +2 -1
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +1 -1
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +1 -1
- data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
- data/lib/rubocop/cop/rspec/around_block.rb +2 -2
- data/lib/rubocop/cop/rspec/base.rb +76 -0
- data/lib/rubocop/cop/rspec/be.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +1 -1
- data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +6 -3
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +1 -1
- data/lib/rubocop/cop/rspec/context_method.rb +2 -2
- data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
- data/lib/rubocop/cop/rspec/cop.rb +2 -66
- data/lib/rubocop/cop/rspec/describe_class.rb +40 -30
- data/lib/rubocop/cop/rspec/describe_method.rb +14 -6
- data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
- data/lib/rubocop/cop/rspec/described_class.rb +2 -2
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
- data/lib/rubocop/cop/rspec/dialect.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +124 -6
- data/lib/rubocop/cop/rspec/empty_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +4 -8
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +4 -8
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +7 -10
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +4 -8
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +5 -8
- data/lib/rubocop/cop/rspec/example_length.rb +1 -1
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +4 -4
- data/lib/rubocop/cop/rspec/expect_actual.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_change.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +3 -3
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +10 -6
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +1 -1
- data/lib/rubocop/cop/rspec/file_path.rb +25 -17
- data/lib/rubocop/cop/rspec/focus.rb +7 -11
- data/lib/rubocop/cop/rspec/hook_argument.rb +5 -6
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +2 -3
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -6
- data/lib/rubocop/cop/rspec/instance_spy.rb +1 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +1 -1
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +1 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +1 -1
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/leading_subject.rb +24 -17
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/let_setup.rb +6 -3
- data/lib/rubocop/cop/rspec/message_chain.rb +1 -1
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +1 -1
- data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +1 -1
- data/lib/rubocop/cop/rspec/named_subject.rb +1 -1
- data/lib/rubocop/cop/rspec/nested_groups.rb +4 -4
- data/lib/rubocop/cop/rspec/not_to_not.rb +1 -1
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/pending.rb +1 -1
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +7 -14
- data/lib/rubocop/cop/rspec/rails/http_status.rb +1 -1
- data/lib/rubocop/cop/rspec/receive_counts.rb +1 -1
- data/lib/rubocop/cop/rspec/receive_never.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +103 -0
- data/lib/rubocop/cop/rspec/return_from_stub.rb +1 -1
- data/lib/rubocop/cop/rspec/scattered_let.rb +1 -1
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_examples.rb +1 -1
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +1 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +172 -0
- data/lib/rubocop/cop/rspec/subject_stub.rb +6 -6
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
- data/lib/rubocop/cop/rspec/variable_definition.rb +6 -6
- data/lib/rubocop/cop/rspec/variable_name.rb +28 -9
- data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
- data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
- data/lib/rubocop/cop/rspec/yield.rb +1 -1
- data/lib/rubocop/cop/rspec_cops.rb +3 -0
- data/lib/rubocop/rspec/corrector/move_node.rb +7 -5
- data/lib/rubocop/rspec/description_extractor.rb +1 -1
- data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -2
- data/lib/rubocop/rspec/example_group.rb +2 -2
- data/lib/rubocop/rspec/hook.rb +1 -5
- data/lib/rubocop/rspec/language.rb +12 -5
- data/lib/rubocop/rspec/language/node_pattern.rb +6 -1
- data/lib/rubocop/rspec/top_level_describe.rb +2 -2
- data/lib/rubocop/rspec/top_level_group.rb +26 -13
- data/lib/rubocop/rspec/variable.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +38 -6
@@ -3,7 +3,20 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
# Check that the first argument to the top
|
6
|
+
# Check that the first argument to the top-level describe is a constant.
|
7
|
+
#
|
8
|
+
# It can be configured to ignore strings when certain metadata is passed.
|
9
|
+
#
|
10
|
+
# Ignores Rails and Aruba `type` metadata by default.
|
11
|
+
#
|
12
|
+
# @example `IgnoredMetadata` configuration
|
13
|
+
#
|
14
|
+
# # .rubocop.yml
|
15
|
+
# # RSpec/DescribeClass:
|
16
|
+
# # IgnoredMetadata:
|
17
|
+
# # type:
|
18
|
+
# # - request
|
19
|
+
# # - controller
|
7
20
|
#
|
8
21
|
# @example
|
9
22
|
# # bad
|
@@ -21,50 +34,47 @@ module RuboCop
|
|
21
34
|
#
|
22
35
|
# describe "A feature example", type: :feature do
|
23
36
|
# end
|
24
|
-
class DescribeClass <
|
25
|
-
include RuboCop::RSpec::
|
37
|
+
class DescribeClass < Base
|
38
|
+
include RuboCop::RSpec::TopLevelGroup
|
26
39
|
|
27
40
|
MSG = 'The first argument to describe should be '\
|
28
41
|
'the class or module being tested.'
|
29
42
|
|
30
|
-
def_node_matcher :
|
31
|
-
|
32
|
-
(send #{RSPEC} :describe const ...)
|
33
|
-
(send #{RSPEC} :describe)
|
34
|
-
}
|
43
|
+
def_node_matcher :example_group_with_ignored_metadata?, <<~PATTERN
|
44
|
+
(send #rspec? :describe ... (hash <#ignored_metadata? ...>))
|
35
45
|
PATTERN
|
36
46
|
|
37
|
-
def_node_matcher :
|
38
|
-
(send #
|
39
|
-
(hash <#rails_metadata? ...>)
|
40
|
-
)
|
47
|
+
def_node_matcher :not_a_const_described, <<~PATTERN
|
48
|
+
(send #rspec? :describe $[!const !#string_constant?] ...)
|
41
49
|
PATTERN
|
42
50
|
|
43
|
-
def_node_matcher :
|
44
|
-
(pair
|
45
|
-
(sym :type)
|
46
|
-
(sym {
|
47
|
-
:channel :controller :helper :job :mailer :model :request
|
48
|
-
:routing :view :feature :system :mailbox
|
49
|
-
}
|
50
|
-
)
|
51
|
-
)
|
51
|
+
def_node_matcher :sym_pair, <<~PATTERN
|
52
|
+
(pair $sym $sym)
|
52
53
|
PATTERN
|
53
54
|
|
54
|
-
def
|
55
|
-
return if
|
56
|
-
return if valid_describe?(node)
|
57
|
-
return if describe_with_rails_metadata?(node)
|
58
|
-
return if string_constant_describe?(described_value)
|
55
|
+
def on_top_level_group(node)
|
56
|
+
return if example_group_with_ignored_metadata?(node.send_node)
|
59
57
|
|
60
|
-
|
58
|
+
not_a_const_described(node.send_node) do |described|
|
59
|
+
add_offense(described)
|
60
|
+
end
|
61
61
|
end
|
62
62
|
|
63
63
|
private
|
64
64
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
65
|
+
def ignored_metadata?(node)
|
66
|
+
sym_pair(node) do |key, value|
|
67
|
+
ignored_metadata[key.value.to_s].to_a.include?(value.value.to_s)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def string_constant?(described)
|
72
|
+
described.str_type? &&
|
73
|
+
described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
|
74
|
+
end
|
75
|
+
|
76
|
+
def ignored_metadata
|
77
|
+
cop_config['IgnoredMetadata'] || {}
|
68
78
|
end
|
69
79
|
end
|
70
80
|
end
|
@@ -16,17 +16,25 @@ module RuboCop
|
|
16
16
|
#
|
17
17
|
# describe MyClass, '.my_class_method' do
|
18
18
|
# end
|
19
|
-
class DescribeMethod <
|
20
|
-
include RuboCop::RSpec::
|
19
|
+
class DescribeMethod < Base
|
20
|
+
include RuboCop::RSpec::TopLevelGroup
|
21
21
|
|
22
22
|
MSG = 'The second argument to describe should be the method '\
|
23
23
|
"being tested. '#instance' or '.class'."
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def_node_matcher :second_argument, <<~PATTERN
|
26
|
+
(block
|
27
|
+
(send #rspec? :describe _first_argument $(str _) ...) ...
|
28
|
+
)
|
29
|
+
PATTERN
|
28
30
|
|
29
|
-
|
31
|
+
def on_top_level_group(node)
|
32
|
+
second_argument = second_argument(node)
|
33
|
+
|
34
|
+
return unless second_argument
|
35
|
+
return if second_argument.str_content.start_with?('#', '.')
|
36
|
+
|
37
|
+
add_offense(second_argument)
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
@@ -17,11 +17,11 @@ module RuboCop
|
|
17
17
|
# end
|
18
18
|
#
|
19
19
|
# @see https://github.com/rspec/rspec-core/issues/1610
|
20
|
-
class DescribeSymbol <
|
20
|
+
class DescribeSymbol < Base
|
21
21
|
MSG = 'Avoid describing symbols.'
|
22
22
|
|
23
23
|
def_node_matcher :describe_symbol?, <<-PATTERN
|
24
|
-
(send #
|
24
|
+
(send #rspec? :describe $sym ...)
|
25
25
|
PATTERN
|
26
26
|
|
27
27
|
def on_send(node)
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
# end
|
55
55
|
# end
|
56
56
|
#
|
57
|
-
class DescribedClass <
|
57
|
+
class DescribedClass < Base
|
58
58
|
extend AutoCorrector
|
59
59
|
include ConfigurableEnforcedStyle
|
60
60
|
|
@@ -142,7 +142,7 @@ module RuboCop
|
|
142
142
|
if style == :described_class
|
143
143
|
offensive_described_class?(node)
|
144
144
|
else
|
145
|
-
node.send_type? && node.
|
145
|
+
node.send_type? && node.method?(:described_class)
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
# end
|
20
20
|
#
|
21
21
|
# @see https://github.com/rubocop-hq/rubocop-rspec/issues/735
|
22
|
-
class DescribedClassModuleWrapping <
|
22
|
+
class DescribedClassModuleWrapping < Base
|
23
23
|
MSG = 'Avoid opening modules and defining specs within them.'
|
24
24
|
|
25
25
|
def_node_search :find_rspec_blocks,
|
@@ -33,6 +33,11 @@ module RuboCop
|
|
33
33
|
# end
|
34
34
|
# end
|
35
35
|
#
|
36
|
+
# # good
|
37
|
+
# describe Bacon do
|
38
|
+
# pending 'will add tests later'
|
39
|
+
# end
|
40
|
+
#
|
36
41
|
# @example configuration
|
37
42
|
#
|
38
43
|
# # .rubocop.yml
|
@@ -57,24 +62,137 @@ module RuboCop
|
|
57
62
|
# end
|
58
63
|
# end
|
59
64
|
#
|
60
|
-
class EmptyExampleGroup <
|
65
|
+
class EmptyExampleGroup < Base
|
61
66
|
MSG = 'Empty example group detected.'
|
62
67
|
|
63
|
-
|
68
|
+
# @!method example_group_body(node)
|
69
|
+
# Match example group blocks and yield their body
|
70
|
+
#
|
71
|
+
# @example source that matches
|
72
|
+
# describe 'example group' do
|
73
|
+
# it { is_expected.to be }
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# @param node [RuboCop::AST::Node]
|
77
|
+
# @yield [RuboCop::AST::Node] example group body
|
78
|
+
def_node_matcher :example_group_body, <<~PATTERN
|
79
|
+
(block #{ExampleGroups::ALL.send_pattern} args $_)
|
80
|
+
PATTERN
|
81
|
+
|
82
|
+
# @!method example_or_group_or_include?(node)
|
83
|
+
# Match examples, example groups and includes
|
84
|
+
#
|
85
|
+
# @example source that matches
|
86
|
+
# it { is_expected.to fly }
|
87
|
+
# describe('non-empty example groups too') { }
|
88
|
+
# it_behaves_like 'an animal'
|
89
|
+
# it_behaves_like('a cat') { let(:food) { 'milk' } }
|
90
|
+
# it_has_root_access
|
91
|
+
# skip
|
92
|
+
# it 'will be implemented later'
|
93
|
+
#
|
94
|
+
# @param node [RuboCop::AST::Node]
|
95
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
96
|
+
def_node_matcher :example_or_group_or_include?, <<~PATTERN
|
97
|
+
{
|
98
|
+
#{Examples::ALL.send_pattern}
|
99
|
+
#{Examples::ALL.block_pattern}
|
100
|
+
#{ExampleGroups::ALL.block_pattern}
|
101
|
+
#{Includes::ALL.send_pattern}
|
102
|
+
#{Includes::ALL.block_pattern}
|
103
|
+
(send nil? #custom_include? ...)
|
104
|
+
}
|
105
|
+
PATTERN
|
106
|
+
|
107
|
+
# @!method examples_inside_block?(node)
|
108
|
+
# Match examples defined inside a block which is not a hook
|
109
|
+
#
|
110
|
+
# @example source that matches
|
111
|
+
# %w(r g b).each do |color|
|
112
|
+
# it { is_expected.to have_color(color) }
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# @example source that does not match
|
116
|
+
# before do
|
117
|
+
# it { is_expected.to fall_into_oblivion }
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# @param node [RuboCop::AST::Node]
|
121
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
122
|
+
def_node_matcher :examples_inside_block?, <<~PATTERN
|
123
|
+
(block !#{Hooks::ALL.send_pattern} _ #examples?)
|
124
|
+
PATTERN
|
125
|
+
|
126
|
+
# @!method examples_directly_or_in_block?(node)
|
127
|
+
# Match examples or examples inside blocks
|
128
|
+
#
|
129
|
+
# @example source that matches
|
130
|
+
# it { expect(drink).to be_cold }
|
131
|
+
# context('when winter') { it { expect(drink).to be_hot } }
|
132
|
+
# (1..5).each { |divisor| it { is_expected.to divide_by(divisor) } }
|
133
|
+
#
|
134
|
+
# @param node [RuboCop::AST::Node]
|
135
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
136
|
+
def_node_matcher :examples_directly_or_in_block?, <<~PATTERN
|
64
137
|
{
|
65
|
-
#
|
66
|
-
|
138
|
+
#example_or_group_or_include?
|
139
|
+
#examples_inside_block?
|
140
|
+
}
|
141
|
+
PATTERN
|
142
|
+
|
143
|
+
# @!method examples?(node)
|
144
|
+
# Matches examples defined in scopes where they could run
|
145
|
+
#
|
146
|
+
# @example source that matches
|
147
|
+
# it { expect(myself).to be_run }
|
148
|
+
# describe { it { i_run_as_well } }
|
149
|
+
#
|
150
|
+
# @example source that does not match
|
151
|
+
# before { it { whatever here wont run anyway } }
|
152
|
+
#
|
153
|
+
# @param node [RuboCop::AST::Node]
|
154
|
+
# @return [Array<RuboCop::AST::Node>] matching nodes
|
155
|
+
def_node_matcher :examples?, <<~PATTERN
|
156
|
+
{
|
157
|
+
#examples_directly_or_in_block?
|
158
|
+
(begin <#examples_directly_or_in_block? ...>)
|
67
159
|
}
|
68
160
|
PATTERN
|
69
161
|
|
70
162
|
def on_block(node)
|
71
|
-
return
|
163
|
+
return if node.each_ancestor(:def, :defs).any?
|
164
|
+
return if node.each_ancestor(:block).any? { |block| example?(block) }
|
72
165
|
|
73
|
-
|
166
|
+
example_group_body(node) do |body|
|
167
|
+
add_offense(node.send_node) if offensive?(body)
|
168
|
+
end
|
74
169
|
end
|
75
170
|
|
76
171
|
private
|
77
172
|
|
173
|
+
def offensive?(body)
|
174
|
+
return true unless body
|
175
|
+
return false if conditionals_with_examples?(body)
|
176
|
+
|
177
|
+
if body.if_type?
|
178
|
+
!examples_in_branches?(body)
|
179
|
+
else
|
180
|
+
!examples?(body)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def conditionals_with_examples?(body)
|
185
|
+
return unless body.begin_type?
|
186
|
+
|
187
|
+
body.each_descendant(:if).any? do |if_node|
|
188
|
+
examples_in_branches?(if_node)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def examples_in_branches?(if_node)
|
193
|
+
if_node.branches.any? { |branch| examples?(branch) }
|
194
|
+
end
|
195
|
+
|
78
196
|
def custom_include?(method_name)
|
79
197
|
custom_include_methods.include?(method_name)
|
80
198
|
end
|
@@ -41,22 +41,18 @@ module RuboCop
|
|
41
41
|
# it { two }
|
42
42
|
# end
|
43
43
|
#
|
44
|
-
class EmptyLineAfterExample <
|
44
|
+
class EmptyLineAfterExample < Base
|
45
45
|
extend AutoCorrector
|
46
|
-
include RuboCop::RSpec::
|
46
|
+
include RuboCop::RSpec::EmptyLineSeparation
|
47
47
|
|
48
48
|
MSG = 'Add an empty line after `%<example>s`.'
|
49
49
|
|
50
50
|
def on_block(node)
|
51
51
|
return unless example?(node)
|
52
|
-
return if last_child?(node)
|
53
52
|
return if allowed_one_liner?(node)
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
add_offense(location, message: msg) do |corrector|
|
58
|
-
corrector.insert_after(location.end, "\n")
|
59
|
-
end
|
54
|
+
missing_separating_line_offense(node) do |method|
|
55
|
+
format(MSG, example: method)
|
60
56
|
end
|
61
57
|
end
|
62
58
|
|
@@ -23,21 +23,17 @@ module RuboCop
|
|
23
23
|
# end
|
24
24
|
# end
|
25
25
|
#
|
26
|
-
class EmptyLineAfterExampleGroup <
|
26
|
+
class EmptyLineAfterExampleGroup < Base
|
27
27
|
extend AutoCorrector
|
28
|
-
include RuboCop::RSpec::
|
28
|
+
include RuboCop::RSpec::EmptyLineSeparation
|
29
29
|
|
30
30
|
MSG = 'Add an empty line after `%<example_group>s`.'
|
31
31
|
|
32
32
|
def on_block(node)
|
33
33
|
return unless example_group?(node)
|
34
|
-
return if last_child?(node)
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
add_offense(location, message: msg) do |corrector|
|
39
|
-
corrector.insert_after(location.end, "\n")
|
40
|
-
end
|
35
|
+
missing_separating_line_offense(node) do |method|
|
36
|
+
format(MSG, example_group: method)
|
41
37
|
end
|
42
38
|
end
|
43
39
|
end
|
@@ -16,24 +16,21 @@ module RuboCop
|
|
16
16
|
# let(:something) { other }
|
17
17
|
#
|
18
18
|
# it { does_something }
|
19
|
-
class EmptyLineAfterFinalLet <
|
19
|
+
class EmptyLineAfterFinalLet < Base
|
20
20
|
extend AutoCorrector
|
21
|
-
include RuboCop::RSpec::
|
21
|
+
include RuboCop::RSpec::EmptyLineSeparation
|
22
22
|
|
23
|
-
MSG = 'Add an empty line after the last
|
23
|
+
MSG = 'Add an empty line after the last `%<let>s`.'
|
24
24
|
|
25
25
|
def on_block(node)
|
26
26
|
return unless example_group_with_body?(node)
|
27
27
|
|
28
|
-
|
28
|
+
final_let = node.body.child_nodes.reverse.find { |child| let?(child) }
|
29
29
|
|
30
|
-
return if
|
31
|
-
return if last_child?(latest_let)
|
30
|
+
return if final_let.nil?
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
corrector.insert_after(location.end, "\n")
|
36
|
-
end
|
32
|
+
missing_separating_line_offense(final_let) do |method|
|
33
|
+
format(MSG, let: method)
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
@@ -33,21 +33,17 @@ module RuboCop
|
|
33
33
|
#
|
34
34
|
# it { does_something }
|
35
35
|
#
|
36
|
-
class EmptyLineAfterHook <
|
36
|
+
class EmptyLineAfterHook < Base
|
37
37
|
extend AutoCorrector
|
38
|
-
include RuboCop::RSpec::
|
38
|
+
include RuboCop::RSpec::EmptyLineSeparation
|
39
39
|
|
40
40
|
MSG = 'Add an empty line after `%<hook>s`.'
|
41
41
|
|
42
42
|
def on_block(node)
|
43
43
|
return unless hook?(node)
|
44
|
-
return if last_child?(node)
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
add_offense(location, message: msg) do |corrector|
|
49
|
-
corrector.insert_after(location.end, "\n")
|
50
|
-
end
|
45
|
+
missing_separating_line_offense(node) do |method|
|
46
|
+
format(MSG, hook: method)
|
51
47
|
end
|
52
48
|
end
|
53
49
|
end
|