rubocop-rspec 2.0.0.pre → 2.3.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 +39 -2
- data/README.md +7 -3
- data/config/default.yml +159 -73
- data/lib/rubocop-rspec.rb +8 -8
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +7 -3
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +7 -3
- data/lib/rubocop/cop/rspec/any_instance.rb +6 -10
- data/lib/rubocop/cop/rspec/around_block.rb +3 -1
- data/lib/rubocop/cop/rspec/base.rb +6 -55
- data/lib/rubocop/cop/rspec/be.rb +3 -2
- data/lib/rubocop/cop/rspec/be_eql.rb +2 -0
- data/lib/rubocop/cop/rspec/before_after_all.rb +6 -3
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +7 -2
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +6 -2
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +4 -0
- data/lib/rubocop/cop/rspec/context_method.rb +1 -0
- data/lib/rubocop/cop/rspec/context_wording.rb +7 -1
- data/lib/rubocop/cop/rspec/describe_class.rb +5 -2
- data/lib/rubocop/cop/rspec/describe_method.rb +3 -2
- data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -0
- data/lib/rubocop/cop/rspec/described_class.rb +6 -2
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +3 -3
- data/lib/rubocop/cop/rspec/dialect.rb +2 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +6 -45
- data/lib/rubocop/cop/rspec/empty_hook.rb +2 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +2 -2
- data/lib/rubocop/cop/rspec/example_length.rb +26 -12
- data/lib/rubocop/cop/rspec/example_without_description.rb +1 -0
- data/lib/rubocop/cop/rspec/example_wording.rb +1 -0
- data/lib/rubocop/cop/rspec/expect_actual.rb +3 -1
- data/lib/rubocop/cop/rspec/expect_change.rb +3 -0
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +2 -1
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +3 -0
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +4 -0
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +2 -0
- data/lib/rubocop/cop/rspec/file_path.rb +26 -17
- data/lib/rubocop/cop/rspec/focus.rb +46 -8
- data/lib/rubocop/cop/rspec/hook_argument.rb +4 -4
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +3 -2
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +4 -0
- data/lib/rubocop/cop/rspec/implicit_expect.rb +2 -1
- data/lib/rubocop/cop/rspec/implicit_subject.rb +2 -0
- data/lib/rubocop/cop/rspec/instance_spy.rb +3 -1
- data/lib/rubocop/cop/rspec/instance_variable.rb +5 -1
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +3 -1
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +3 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +3 -2
- data/lib/rubocop/cop/rspec/let_setup.rb +10 -4
- data/lib/rubocop/cop/rspec/message_chain.rb +4 -10
- data/lib/rubocop/cop/rspec/message_expectation.rb +3 -0
- data/lib/rubocop/cop/rspec/message_spies.rb +5 -3
- data/lib/rubocop/cop/rspec/mixin/comments_help.rb +38 -0
- data/lib/rubocop/cop/rspec/mixin/empty_line_separation.rb +51 -0
- data/lib/rubocop/cop/rspec/mixin/final_end_location.rb +19 -0
- data/lib/rubocop/cop/rspec/mixin/top_level_group.rb +54 -0
- data/lib/rubocop/cop/rspec/mixin/variable.rb +21 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +4 -1
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
- data/lib/rubocop/cop/rspec/named_subject.rb +11 -12
- data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
- data/lib/rubocop/cop/rspec/not_to_not.rb +2 -0
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +4 -1
- data/lib/rubocop/cop/rspec/pending.rb +17 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +8 -3
- data/lib/rubocop/cop/rspec/rails/http_status.rb +2 -0
- data/lib/rubocop/cop/rspec/receive_counts.rb +4 -0
- data/lib/rubocop/cop/rspec/receive_never.rb +2 -0
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +8 -1
- data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +4 -0
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +6 -2
- data/lib/rubocop/cop/rspec/return_from_stub.rb +6 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +22 -11
- data/lib/rubocop/cop/rspec/shared_examples.rb +4 -1
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +4 -1
- data/lib/rubocop/cop/rspec/stubbed_mock.rb +2 -1
- data/lib/rubocop/cop/rspec/subject_stub.rb +17 -6
- data/lib/rubocop/cop/rspec/unspecified_exception.rb +2 -0
- 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/verified_doubles.rb +2 -0
- data/lib/rubocop/cop/rspec/void_expect.rb +3 -0
- data/lib/rubocop/cop/rspec/yield.rb +3 -0
- data/lib/rubocop/cop/rspec_cops.rb +0 -1
- data/lib/rubocop/rspec/align_let_brace.rb +1 -1
- data/lib/rubocop/rspec/concept.rb +2 -2
- data/lib/rubocop/rspec/config_formatter.rb +5 -3
- data/lib/rubocop/rspec/corrector/move_node.rb +7 -10
- data/lib/rubocop/rspec/example.rb +5 -0
- data/lib/rubocop/rspec/example_group.rb +15 -5
- data/lib/rubocop/rspec/hook.rb +2 -1
- data/lib/rubocop/rspec/inject.rb +4 -2
- data/lib/rubocop/rspec/language.rb +159 -115
- data/lib/rubocop/rspec/language/node_pattern.rb +7 -24
- data/lib/rubocop/rspec/node.rb +1 -1
- data/lib/rubocop/rspec/version.rb +1 -1
- metadata +27 -16
- data/lib/rubocop/cop/rspec/cop.rb +0 -10
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +0 -41
- data/lib/rubocop/rspec.rb +0 -12
- data/lib/rubocop/rspec/empty_line_separation.rb +0 -48
- data/lib/rubocop/rspec/final_end_location.rb +0 -17
- data/lib/rubocop/rspec/top_level_describe.rb +0 -52
- data/lib/rubocop/rspec/top_level_group.rb +0 -57
- data/lib/rubocop/rspec/variable.rb +0 -16
@@ -20,25 +20,43 @@ module RuboCop
|
|
20
20
|
# describe MyClass do
|
21
21
|
# end
|
22
22
|
class Focus < Base
|
23
|
-
|
23
|
+
extend AutoCorrector
|
24
|
+
include RangeHelp
|
24
25
|
|
25
|
-
|
26
|
+
MSG = 'Focused spec found.'
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
# @!method focusable_selector?(node)
|
29
|
+
def_node_matcher :focusable_selector?, <<-PATTERN
|
30
|
+
{
|
31
|
+
#ExampleGroups.regular
|
32
|
+
#ExampleGroups.skipped
|
33
|
+
#Examples.regular
|
34
|
+
#Examples.skipped
|
35
|
+
#Examples.pending
|
36
|
+
}
|
37
|
+
PATTERN
|
31
38
|
|
39
|
+
# @!method metadata(node)
|
32
40
|
def_node_matcher :metadata, <<-PATTERN
|
33
41
|
{(send #rspec? #focusable_selector? <$(sym :focus) ...>)
|
34
42
|
(send #rspec? #focusable_selector? ... (hash <$(pair (sym :focus) true) ...>))}
|
35
43
|
PATTERN
|
36
44
|
|
37
|
-
|
45
|
+
# @!method focused_block?(node)
|
46
|
+
def_node_matcher :focused_block?,
|
47
|
+
send_pattern(<<~PATTERN)
|
48
|
+
{#ExampleGroups.focused #Examples.focused}
|
49
|
+
PATTERN
|
38
50
|
|
39
51
|
def on_send(node)
|
40
52
|
focus_metadata(node) do |focus|
|
41
|
-
add_offense(focus)
|
53
|
+
add_offense(focus) do |corrector|
|
54
|
+
if focus.pair_type? || focus.str_type? || focus.sym_type?
|
55
|
+
corrector.remove(with_surrounding(focus))
|
56
|
+
elsif focus.send_type?
|
57
|
+
correct_send(corrector, focus)
|
58
|
+
end
|
59
|
+
end
|
42
60
|
end
|
43
61
|
end
|
44
62
|
|
@@ -49,6 +67,26 @@ module RuboCop
|
|
49
67
|
|
50
68
|
metadata(node, &block)
|
51
69
|
end
|
70
|
+
|
71
|
+
def with_surrounding(focus)
|
72
|
+
range_with_space = range_with_surrounding_space(
|
73
|
+
range: focus.loc.expression,
|
74
|
+
side: :left
|
75
|
+
)
|
76
|
+
|
77
|
+
range_with_surrounding_comma(range_with_space, :left)
|
78
|
+
end
|
79
|
+
|
80
|
+
def correct_send(corrector, focus)
|
81
|
+
range = focus.loc.selector
|
82
|
+
unfocused = focus.method_name.to_s.sub(/^f/, '')
|
83
|
+
unless Examples.regular(unfocused) || ExampleGroups.regular(unfocused)
|
84
|
+
return
|
85
|
+
end
|
86
|
+
|
87
|
+
corrector.replace(range,
|
88
|
+
range.source.sub(focus.method_name.to_s, unfocused))
|
89
|
+
end
|
52
90
|
end
|
53
91
|
end
|
54
92
|
end
|
@@ -64,13 +64,13 @@ module RuboCop
|
|
64
64
|
IMPLICIT_MSG = 'Omit the default `%<scope>p` argument for RSpec hooks.'
|
65
65
|
EXPLICIT_MSG = 'Use `%<scope>p` for RSpec hooks.'
|
66
66
|
|
67
|
-
|
68
|
-
|
67
|
+
# @!method scoped_hook(node)
|
69
68
|
def_node_matcher :scoped_hook, <<-PATTERN
|
70
|
-
(block $(send _ #
|
69
|
+
(block $(send _ #Hooks.all (sym ${:each :example})) ...)
|
71
70
|
PATTERN
|
72
71
|
|
73
|
-
|
72
|
+
# @!method unscoped_hook(node)
|
73
|
+
def_node_matcher :unscoped_hook, '(block $(send _ #Hooks.all) ...)'
|
74
74
|
|
75
75
|
def on_block(node)
|
76
76
|
hook(node) do |method_send, scope_name|
|
@@ -28,10 +28,11 @@ module RuboCop
|
|
28
28
|
|
29
29
|
MSG = 'Move `%<hook>s` above the examples in the group.'
|
30
30
|
|
31
|
+
# @!method example_or_group?(node)
|
31
32
|
def_node_matcher :example_or_group?, <<-PATTERN
|
32
33
|
{
|
33
|
-
#{(
|
34
|
-
#{Includes
|
34
|
+
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
|
35
|
+
#{send_pattern('#Includes.examples')}
|
35
36
|
}
|
36
37
|
PATTERN
|
37
38
|
|
@@ -18,7 +18,9 @@ module RuboCop
|
|
18
18
|
# end
|
19
19
|
class ImplicitBlockExpectation < Base
|
20
20
|
MSG = 'Avoid implicit block expectations.'
|
21
|
+
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
21
22
|
|
23
|
+
# @!method lambda?(node)
|
22
24
|
def_node_matcher :lambda?, <<-PATTERN
|
23
25
|
{
|
24
26
|
(send (const nil? :Proc) :new)
|
@@ -26,8 +28,10 @@ module RuboCop
|
|
26
28
|
}
|
27
29
|
PATTERN
|
28
30
|
|
31
|
+
# @!method lambda_subject?(node)
|
29
32
|
def_node_matcher :lambda_subject?, '(block #lambda? ...)'
|
30
33
|
|
34
|
+
# @!method implicit_expect(node)
|
31
35
|
def_node_matcher :implicit_expect, <<-PATTERN
|
32
36
|
$(send nil? {:is_expected :should :should_not} ...)
|
33
37
|
PATTERN
|
@@ -30,10 +30,11 @@ module RuboCop
|
|
30
30
|
|
31
31
|
MSG = 'Prefer `%<good>s` over `%<bad>s`.'
|
32
32
|
|
33
|
+
# @!method implicit_expect(node)
|
33
34
|
def_node_matcher :implicit_expect, <<-PATTERN
|
34
35
|
{
|
35
36
|
(send nil? ${:should :should_not} ...)
|
36
|
-
(send (send nil? $:is_expected) #
|
37
|
+
(send (send nil? $:is_expected) #Runners.all ...)
|
37
38
|
}
|
38
39
|
PATTERN
|
39
40
|
|
@@ -31,7 +31,9 @@ module RuboCop
|
|
31
31
|
include ConfigurableEnforcedStyle
|
32
32
|
|
33
33
|
MSG = "Don't use implicit subject."
|
34
|
+
RESTRICT_ON_SEND = %i[is_expected should should_not].freeze
|
34
35
|
|
36
|
+
# @!method implicit_subject?(node)
|
35
37
|
def_node_matcher :implicit_subject?, <<-PATTERN
|
36
38
|
(send nil? {:should :should_not :is_expected} ...)
|
37
39
|
PATTERN
|
@@ -21,9 +21,10 @@ module RuboCop
|
|
21
21
|
class InstanceSpy < Base
|
22
22
|
extend AutoCorrector
|
23
23
|
|
24
|
-
MSG = 'Use `instance_spy` when you check your double '\
|
24
|
+
MSG = 'Use `instance_spy` when you check your double ' \
|
25
25
|
'with `have_received`.'
|
26
26
|
|
27
|
+
# @!method null_double(node)
|
27
28
|
def_node_search :null_double, <<-PATTERN
|
28
29
|
(lvasgn $_
|
29
30
|
(send
|
@@ -31,6 +32,7 @@ module RuboCop
|
|
31
32
|
...) :as_null_object))
|
32
33
|
PATTERN
|
33
34
|
|
35
|
+
# @!method have_received_usage(node)
|
34
36
|
def_node_search :have_received_usage, <<-PATTERN
|
35
37
|
(send
|
36
38
|
(send nil? :expect
|
@@ -47,15 +47,17 @@ module RuboCop
|
|
47
47
|
# end
|
48
48
|
#
|
49
49
|
class InstanceVariable < Base
|
50
|
-
include
|
50
|
+
include TopLevelGroup
|
51
51
|
|
52
52
|
MSG = 'Avoid instance variables – use let, ' \
|
53
53
|
'a method call, or a local variable (if possible).'
|
54
54
|
|
55
|
+
# @!method dynamic_class?(node)
|
55
56
|
def_node_matcher :dynamic_class?, <<-PATTERN
|
56
57
|
(block (send (const nil? :Class) :new ...) ...)
|
57
58
|
PATTERN
|
58
59
|
|
60
|
+
# @!method custom_matcher?(node)
|
59
61
|
def_node_matcher :custom_matcher?, <<-PATTERN
|
60
62
|
(block {
|
61
63
|
(send nil? :matcher sym)
|
@@ -63,8 +65,10 @@ module RuboCop
|
|
63
65
|
} ...)
|
64
66
|
PATTERN
|
65
67
|
|
68
|
+
# @!method ivar_usage(node)
|
66
69
|
def_node_search :ivar_usage, '$(ivar $_)'
|
67
70
|
|
71
|
+
# @!method ivar_assigned?(node)
|
68
72
|
def_node_search :ivar_assigned?, '(ivasgn % ...)'
|
69
73
|
|
70
74
|
def on_top_level_group(node)
|
@@ -22,9 +22,11 @@ module RuboCop
|
|
22
22
|
extend AutoCorrector
|
23
23
|
include ConfigurableEnforcedStyle
|
24
24
|
|
25
|
-
MSG = 'Prefer `%<replacement>s` over `%<original>s` when including '\
|
25
|
+
MSG = 'Prefer `%<replacement>s` over `%<original>s` when including ' \
|
26
26
|
'examples in a nested context.'
|
27
|
+
RESTRICT_ON_SEND = %i[it_behaves_like it_should_behave_like].freeze
|
27
28
|
|
29
|
+
# @!method example_inclusion_offense(node)
|
28
30
|
def_node_matcher :example_inclusion_offense, '(send _ % ...)'
|
29
31
|
|
30
32
|
def on_send(node)
|
@@ -17,8 +17,9 @@ module RuboCop
|
|
17
17
|
# end
|
18
18
|
class IteratedExpectation < Base
|
19
19
|
MSG = 'Prefer using the `all` matcher instead ' \
|
20
|
-
|
20
|
+
'of iterating over an array.'
|
21
21
|
|
22
|
+
# @!method each?(node)
|
22
23
|
def_node_matcher :each?, <<-PATTERN
|
23
24
|
(block
|
24
25
|
(send ... :each)
|
@@ -27,6 +28,7 @@ module RuboCop
|
|
27
28
|
)
|
28
29
|
PATTERN
|
29
30
|
|
31
|
+
# @!method expectation?(node)
|
30
32
|
def_node_matcher :expectation?, <<-PATTERN
|
31
33
|
(send (send nil? :expect (lvar %)) :to ...)
|
32
34
|
PATTERN
|
@@ -35,10 +35,11 @@ module RuboCop
|
|
35
35
|
|
36
36
|
MSG = 'Move `let` before the examples in the group.'
|
37
37
|
|
38
|
+
# @!method example_or_group?(node)
|
38
39
|
def_node_matcher :example_or_group?, <<-PATTERN
|
39
40
|
{
|
40
|
-
#{(
|
41
|
-
#{Includes
|
41
|
+
#{block_pattern('{#ExampleGroups.all #Examples.all}')}
|
42
|
+
#{send_pattern('#Includes.examples')}
|
42
43
|
}
|
43
44
|
PATTERN
|
44
45
|
|
@@ -28,12 +28,17 @@ module RuboCop
|
|
28
28
|
class LetSetup < Base
|
29
29
|
MSG = 'Do not use `let!` to setup objects not referenced in tests.'
|
30
30
|
|
31
|
+
# @!method example_or_shared_group_or_including?(node)
|
31
32
|
def_node_matcher :example_or_shared_group_or_including?,
|
32
|
-
(
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
block_pattern(<<~PATTERN)
|
34
|
+
{
|
35
|
+
#SharedGroups.all
|
36
|
+
#ExampleGroups.all
|
37
|
+
#Includes.all
|
38
|
+
}
|
39
|
+
PATTERN
|
36
40
|
|
41
|
+
# @!method let_bang(node)
|
37
42
|
def_node_matcher :let_bang, <<-PATTERN
|
38
43
|
{
|
39
44
|
(block $(send nil? :let! {(sym $_) (str $_)}) ...)
|
@@ -41,6 +46,7 @@ module RuboCop
|
|
41
46
|
}
|
42
47
|
PATTERN
|
43
48
|
|
49
|
+
# @!method method_called?(node)
|
44
50
|
def_node_search :method_called?, '(send nil? %)'
|
45
51
|
|
46
52
|
def on_block(node)
|
@@ -15,18 +15,12 @@ module RuboCop
|
|
15
15
|
#
|
16
16
|
class MessageChain < Base
|
17
17
|
MSG = 'Avoid stubbing using `%<method>s`.'
|
18
|
-
|
19
|
-
def_node_matcher :message_chain, <<-PATTERN
|
20
|
-
(send _ {:receive_message_chain :stub_chain} ...)
|
21
|
-
PATTERN
|
18
|
+
RESTRICT_ON_SEND = %i[receive_message_chain stub_chain].freeze
|
22
19
|
|
23
20
|
def on_send(node)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
message: format(MSG, method: node.method_name)
|
28
|
-
)
|
29
|
-
end
|
21
|
+
add_offense(
|
22
|
+
node.loc.selector, message: format(MSG, method: node.method_name)
|
23
|
+
)
|
30
24
|
end
|
31
25
|
end
|
32
26
|
end
|
@@ -30,11 +30,14 @@ module RuboCop
|
|
30
30
|
MSG = 'Prefer `%<style>s` for setting message expectations.'
|
31
31
|
|
32
32
|
SUPPORTED_STYLES = %w[allow expect].freeze
|
33
|
+
RESTRICT_ON_SEND = %i[to].freeze
|
33
34
|
|
35
|
+
# @!method message_expectation(node)
|
34
36
|
def_node_matcher :message_expectation, <<-PATTERN
|
35
37
|
(send $(send nil? {:expect :allow} ...) :to #receive_message?)
|
36
38
|
PATTERN
|
37
39
|
|
40
|
+
# @!method receive_message?(node)
|
38
41
|
def_node_search :receive_message?, '(send nil? :receive ...)'
|
39
42
|
|
40
43
|
def on_send(node)
|
@@ -29,16 +29,18 @@ module RuboCop
|
|
29
29
|
|
30
30
|
MSG_RECEIVE = 'Prefer `receive` for setting message expectations.'
|
31
31
|
|
32
|
-
MSG_HAVE_RECEIVED = 'Prefer `have_received` for setting message '\
|
33
|
-
'expectations. Setup `%<source>s` as a spy using '\
|
32
|
+
MSG_HAVE_RECEIVED = 'Prefer `have_received` for setting message ' \
|
33
|
+
'expectations. Setup `%<source>s` as a spy using ' \
|
34
34
|
'`allow` or `instance_spy`.'
|
35
35
|
|
36
36
|
SUPPORTED_STYLES = %w[have_received receive].freeze
|
37
37
|
|
38
|
+
# @!method message_expectation(node)
|
38
39
|
def_node_matcher :message_expectation, %(
|
39
|
-
(send (send nil? :expect $_) #
|
40
|
+
(send (send nil? :expect $_) #Runners.all ...)
|
40
41
|
)
|
41
42
|
|
43
|
+
# @!method receive_message(node)
|
42
44
|
def_node_search :receive_message, %(
|
43
45
|
$(send nil? {:receive :have_received} ...)
|
44
46
|
)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Help methods for working with nodes containing comments.
|
7
|
+
module CommentsHelp
|
8
|
+
include FinalEndLocation
|
9
|
+
|
10
|
+
def source_range_with_comment(node)
|
11
|
+
begin_pos = begin_pos_with_comment(node).begin_pos
|
12
|
+
end_pos = end_line_position(node).end_pos
|
13
|
+
|
14
|
+
Parser::Source::Range.new(buffer, begin_pos, end_pos)
|
15
|
+
end
|
16
|
+
|
17
|
+
def begin_pos_with_comment(node)
|
18
|
+
first_comment = processed_source.ast_with_comments[node].first
|
19
|
+
|
20
|
+
start_line_position(first_comment || node)
|
21
|
+
end
|
22
|
+
|
23
|
+
def start_line_position(node)
|
24
|
+
buffer.line_range(node.loc.line)
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_line_position(node)
|
28
|
+
end_line = buffer.line_for_position(final_end_location(node).end_pos)
|
29
|
+
buffer.line_range(end_line)
|
30
|
+
end
|
31
|
+
|
32
|
+
def buffer
|
33
|
+
processed_source.buffer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps determine the offending location if there is not an empty line
|
7
|
+
# following the node. Allows comments to follow directly after.
|
8
|
+
module EmptyLineSeparation
|
9
|
+
include FinalEndLocation
|
10
|
+
include RangeHelp
|
11
|
+
|
12
|
+
def missing_separating_line_offense(node)
|
13
|
+
return if last_child?(node)
|
14
|
+
|
15
|
+
missing_separating_line(node) do |location|
|
16
|
+
msg = yield(node.method_name)
|
17
|
+
add_offense(location, message: msg) do |corrector|
|
18
|
+
corrector.insert_after(location.end, "\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def missing_separating_line(node)
|
24
|
+
line = final_end_location(node).line
|
25
|
+
|
26
|
+
line += 1 while comment_line?(processed_source[line])
|
27
|
+
|
28
|
+
return if processed_source[line].blank?
|
29
|
+
|
30
|
+
yield offending_loc(line)
|
31
|
+
end
|
32
|
+
|
33
|
+
def offending_loc(last_line)
|
34
|
+
offending_line = processed_source[last_line - 1]
|
35
|
+
|
36
|
+
content_length = offending_line.lstrip.length
|
37
|
+
start = offending_line.length - content_length
|
38
|
+
|
39
|
+
source_range(processed_source.buffer,
|
40
|
+
last_line, start, content_length)
|
41
|
+
end
|
42
|
+
|
43
|
+
def last_child?(node)
|
44
|
+
return true unless node.parent&.begin_type?
|
45
|
+
|
46
|
+
node.equal?(node.parent.children.last)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Helps find the true end location of nodes which might contain heredocs.
|
7
|
+
module FinalEndLocation
|
8
|
+
def final_end_location(start_node)
|
9
|
+
heredoc_endings =
|
10
|
+
start_node.each_node(:str, :dstr, :xstr)
|
11
|
+
.select(&:heredoc?)
|
12
|
+
.map { |node| node.loc.heredoc_end }
|
13
|
+
|
14
|
+
[start_node.loc.end, *heredoc_endings].max_by(&:line)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|