rubocop-rspec 1.38.0 → 1.42.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 +44 -0
- data/CODE_OF_CONDUCT.md +17 -0
- data/README.md +1 -61
- data/config/default.yml +147 -17
- data/lib/rubocop-rspec.rb +3 -1
- data/lib/rubocop/cop/rspec/align_left_let_brace.rb +11 -18
- data/lib/rubocop/cop/rspec/align_right_let_brace.rb +11 -18
- data/lib/rubocop/cop/rspec/be.rb +1 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +5 -5
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +18 -16
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +8 -9
- data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +69 -0
- data/lib/rubocop/cop/rspec/context_method.rb +5 -7
- 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/described_class.rb +10 -7
- data/lib/rubocop/cop/rspec/dialect.rb +4 -11
- data/lib/rubocop/cop/rspec/empty_hook.rb +46 -0
- data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -3
- data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -5
- data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +4 -1
- data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -5
- data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +4 -1
- data/lib/rubocop/cop/rspec/example_wording.rb +6 -7
- data/lib/rubocop/cop/rspec/expect_actual.rb +7 -10
- data/lib/rubocop/cop/rspec/expect_change.rb +9 -34
- data/lib/rubocop/cop/rspec/expect_in_hook.rb +2 -2
- data/lib/rubocop/cop/rspec/expect_output.rb +1 -1
- data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +23 -20
- data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +10 -16
- data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +6 -7
- data/lib/rubocop/cop/rspec/file_path.rb +32 -4
- data/lib/rubocop/cop/rspec/hook_argument.rb +11 -17
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +9 -28
- data/lib/rubocop/cop/rspec/implicit_expect.rb +6 -14
- data/lib/rubocop/cop/rspec/implicit_subject.rb +8 -5
- data/lib/rubocop/cop/rspec/instance_spy.rb +17 -11
- data/lib/rubocop/cop/rspec/instance_variable.rb +3 -7
- data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +2 -5
- data/lib/rubocop/cop/rspec/it_behaves_like.rb +4 -5
- data/lib/rubocop/cop/rspec/leading_subject.rb +12 -19
- data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +1 -4
- data/lib/rubocop/cop/rspec/let_before_examples.rb +9 -25
- data/lib/rubocop/cop/rspec/let_setup.rb +15 -3
- data/lib/rubocop/cop/rspec/message_chain.rb +6 -5
- data/lib/rubocop/cop/rspec/message_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/message_spies.rb +1 -2
- data/lib/rubocop/cop/rspec/multiple_subjects.rb +17 -18
- data/lib/rubocop/cop/rspec/named_subject.rb +7 -7
- data/lib/rubocop/cop/rspec/nested_groups.rb +9 -10
- data/lib/rubocop/cop/rspec/not_to_not.rb +4 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +25 -55
- data/lib/rubocop/cop/rspec/rails/http_status.rb +6 -8
- data/lib/rubocop/cop/rspec/receive_counts.rb +14 -16
- data/lib/rubocop/cop/rspec/receive_never.rb +10 -10
- data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +11 -1
- data/lib/rubocop/cop/rspec/return_from_stub.rb +11 -21
- data/lib/rubocop/cop/rspec/scattered_let.rb +11 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +7 -20
- data/lib/rubocop/cop/rspec/shared_examples.rb +6 -8
- data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +14 -17
- 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/yield.rb +13 -10
- data/lib/rubocop/cop/rspec_cops.rb +5 -1
- data/lib/rubocop/rspec/blank_line_separation.rb +0 -8
- 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/language.rb +8 -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 +17 -10
- data/lib/rubocop/rspec/util.rb +0 -19
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks that memoized helpers names are symbols or strings.
|
7
|
+
#
|
8
|
+
# @example EnforcedStyle: symbols (default)
|
9
|
+
# # bad
|
10
|
+
# let('user_name') { 'Adam' }
|
11
|
+
# subject('user') { create_user }
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# let(:user_name) { 'Adam' }
|
15
|
+
# subject(:user) { create_user }
|
16
|
+
#
|
17
|
+
# @example EnforcedStyle: strings
|
18
|
+
# # bad
|
19
|
+
# let(:user_name) { 'Adam' }
|
20
|
+
# subject(:user) { create_user }
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# let('user_name') { 'Adam' }
|
24
|
+
# subject('user') { create_user }
|
25
|
+
class VariableDefinition < Cop
|
26
|
+
include ConfigurableEnforcedStyle
|
27
|
+
include RuboCop::RSpec::Variable
|
28
|
+
|
29
|
+
MSG = 'Use %<style>s for variable names.'
|
30
|
+
|
31
|
+
def on_send(node)
|
32
|
+
variable_definition?(node) do |variable|
|
33
|
+
if style_violation?(variable)
|
34
|
+
add_offense(variable, message: format(MSG, style: style))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def style_violation?(variable)
|
42
|
+
style == :symbols && string?(variable) ||
|
43
|
+
style == :strings && symbol?(variable)
|
44
|
+
end
|
45
|
+
|
46
|
+
def string?(node)
|
47
|
+
node.str_type? || node.dstr_type?
|
48
|
+
end
|
49
|
+
|
50
|
+
def symbol?(node)
|
51
|
+
node.sym_type? || node.dsym_type?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks that memoized helper names use the configured style.
|
7
|
+
#
|
8
|
+
# @example EnforcedStyle: snake_case (default)
|
9
|
+
# # bad
|
10
|
+
# let(:userName) { 'Adam' }
|
11
|
+
# subject(:userName) { 'Adam' }
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# let(:user_name) { 'Adam' }
|
15
|
+
# subject(:user_name) { 'Adam' }
|
16
|
+
#
|
17
|
+
# @example EnforcedStyle: camelCase
|
18
|
+
# # bad
|
19
|
+
# let(:user_name) { 'Adam' }
|
20
|
+
# subject(:user_name) { 'Adam' }
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# let(:userName) { 'Adam' }
|
24
|
+
# subject(:userName) { 'Adam' }
|
25
|
+
class VariableName < Cop
|
26
|
+
include ConfigurableNaming
|
27
|
+
include RuboCop::RSpec::Variable
|
28
|
+
|
29
|
+
MSG = 'Use %<style>s for variable names.'
|
30
|
+
|
31
|
+
def on_send(node)
|
32
|
+
variable_definition?(node) do |variable|
|
33
|
+
return if variable.dstr_type? || variable.dsym_type?
|
34
|
+
|
35
|
+
check_name(node, variable.value, variable.loc.expression)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def message(style)
|
42
|
+
format(MSG, style: style)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
# # good
|
13
13
|
# expect(foo).to be(:bar).and_yield(1)
|
14
14
|
class Yield < Cop
|
15
|
+
extend AutoCorrector
|
15
16
|
include RangeHelp
|
16
17
|
|
17
18
|
MSG = 'Use `.and_yield`.'
|
@@ -27,22 +28,24 @@ module RuboCop
|
|
27
28
|
|
28
29
|
block_arg(node.arguments) do |block|
|
29
30
|
if calling_block?(node.body, block)
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
31
|
+
range = block_range(node)
|
34
32
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
)
|
40
|
-
corrector.replace(node_range, generate_replacement(node.body))
|
33
|
+
add_offense(range) do |corrector|
|
34
|
+
autocorrect(corrector, node, range)
|
35
|
+
end
|
36
|
+
end
|
41
37
|
end
|
42
38
|
end
|
43
39
|
|
44
40
|
private
|
45
41
|
|
42
|
+
def autocorrect(corrector, node, range)
|
43
|
+
corrector.replace(
|
44
|
+
range_with_surrounding_space(range: range, side: :left),
|
45
|
+
generate_replacement(node.body)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
46
49
|
def calling_block?(node, block)
|
47
50
|
if node.begin_type?
|
48
51
|
node.each_child_node.all? { |child| block_call?(child, block) }
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'rspec/capybara/current_path_expectation'
|
4
4
|
require_relative 'rspec/capybara/feature_methods'
|
5
|
+
require_relative 'rspec/capybara/visibility_matcher'
|
5
6
|
|
6
7
|
require_relative 'rspec/factory_bot/attribute_defined_statically'
|
7
8
|
require_relative 'rspec/factory_bot/create_list'
|
@@ -9,7 +10,7 @@ require_relative 'rspec/factory_bot/factory_class_name'
|
|
9
10
|
|
10
11
|
begin
|
11
12
|
require_relative 'rspec/rails/http_status'
|
12
|
-
rescue LoadError
|
13
|
+
rescue LoadError
|
13
14
|
# Rails/HttpStatus cannot be loaded if rack/utils is unavailable.
|
14
15
|
end
|
15
16
|
|
@@ -29,6 +30,7 @@ require_relative 'rspec/described_class'
|
|
29
30
|
require_relative 'rspec/described_class_module_wrapping'
|
30
31
|
require_relative 'rspec/dialect'
|
31
32
|
require_relative 'rspec/empty_example_group'
|
33
|
+
require_relative 'rspec/empty_hook'
|
32
34
|
require_relative 'rspec/empty_line_after_example'
|
33
35
|
require_relative 'rspec/empty_line_after_example_group'
|
34
36
|
require_relative 'rspec/empty_line_after_final_let'
|
@@ -84,6 +86,8 @@ require_relative 'rspec/shared_examples'
|
|
84
86
|
require_relative 'rspec/single_argument_message_chain'
|
85
87
|
require_relative 'rspec/subject_stub'
|
86
88
|
require_relative 'rspec/unspecified_exception'
|
89
|
+
require_relative 'rspec/variable_definition'
|
90
|
+
require_relative 'rspec/variable_name'
|
87
91
|
require_relative 'rspec/verified_doubles'
|
88
92
|
require_relative 'rspec/void_expect'
|
89
93
|
require_relative 'rspec/yield'
|
@@ -32,14 +32,6 @@ module RuboCop
|
|
32
32
|
|
33
33
|
node.equal?(node.parent.children.last)
|
34
34
|
end
|
35
|
-
|
36
|
-
def autocorrect(node)
|
37
|
-
lambda do |corrector|
|
38
|
-
missing_separating_line(node) do |location|
|
39
|
-
corrector.insert_after(location.end, "\n")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
35
|
end
|
44
36
|
end
|
45
37
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module RSpec
|
5
|
+
module Corrector
|
6
|
+
# Helper methods to move a node
|
7
|
+
class MoveNode
|
8
|
+
include RuboCop::Cop::RangeHelp
|
9
|
+
include RuboCop::RSpec::FinalEndLocation
|
10
|
+
|
11
|
+
attr_reader :original, :corrector, :processed_source
|
12
|
+
|
13
|
+
def initialize(node, corrector, processed_source)
|
14
|
+
@original = node
|
15
|
+
@corrector = corrector
|
16
|
+
@processed_source = processed_source # used by RangeHelp
|
17
|
+
end
|
18
|
+
|
19
|
+
def move_before(other) # rubocop:disable Metrics/AbcSize
|
20
|
+
position = other.loc.expression
|
21
|
+
indent = "\n" + ' ' * other.loc.column
|
22
|
+
|
23
|
+
corrector.insert_before(position, source(original) + indent)
|
24
|
+
corrector.remove(node_range_with_surrounding_space(original))
|
25
|
+
end
|
26
|
+
|
27
|
+
def move_after(other)
|
28
|
+
position = final_end_location(other)
|
29
|
+
indent = "\n" + ' ' * other.loc.column
|
30
|
+
|
31
|
+
corrector.insert_after(position, indent + source(original))
|
32
|
+
corrector.remove(node_range_with_surrounding_space(original))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def source(node)
|
38
|
+
node_range(node).source
|
39
|
+
end
|
40
|
+
|
41
|
+
def node_range(node)
|
42
|
+
node.loc.expression.with(end_pos: final_end_location(node).end_pos)
|
43
|
+
end
|
44
|
+
|
45
|
+
def node_range_with_surrounding_space(node)
|
46
|
+
range = node_range(node)
|
47
|
+
range_by_whole_lines(range, include_final_newline: true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -21,7 +21,7 @@ module RuboCop
|
|
21
21
|
|
22
22
|
# Decorator of a YARD code object for working with documented rspec cops
|
23
23
|
class CodeObject
|
24
|
-
|
24
|
+
COP_CLASS_NAME = 'RuboCop::Cop::RSpec::Cop'
|
25
25
|
RSPEC_NAMESPACE = 'RuboCop::Cop::RSpec'
|
26
26
|
|
27
27
|
def initialize(yardoc)
|
@@ -68,11 +68,7 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def cop_subclass?
|
71
|
-
|
72
|
-
# RuboCop::Cop::WorkaroundCop are shown as having RuboCop::Cop as
|
73
|
-
# superclass, while all the following classes are listed as having
|
74
|
-
# RuboCop::Cop::RSpec::Cop as their superclass.
|
75
|
-
COP_CLASS_NAMES.include?(yardoc.superclass.path)
|
71
|
+
yardoc.superclass.path == COP_CLASS_NAME
|
76
72
|
end
|
77
73
|
|
78
74
|
def abstract?
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module RSpec
|
5
5
|
# Wrapper for RSpec examples
|
6
6
|
class Example < Concept
|
7
|
-
def_node_matcher :extract_doc_string, '(send _ _ $
|
7
|
+
def_node_matcher :extract_doc_string, '(send _ _ $_ ...)'
|
8
8
|
def_node_matcher :extract_metadata, '(send _ _ _ $...)'
|
9
9
|
def_node_matcher :extract_implementation, '(block send args $_)'
|
10
10
|
|
@@ -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__
|
@@ -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
|
@@ -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
|