rubocop-rspec 1.43.2 → 2.0.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 +39 -4
- data/README.md +5 -1
- data/config/default.yml +183 -67
- data/lib/rubocop-rspec.rb +7 -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/around_block.rb +2 -2
- data/lib/rubocop/cop/rspec/base.rb +7 -54
- data/lib/rubocop/cop/rspec/be.rb +2 -2
- data/lib/rubocop/cop/rspec/before_after_all.rb +3 -3
- data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +2 -2
- data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +3 -2
- data/lib/rubocop/cop/rspec/describe_class.rb +34 -15
- data/lib/rubocop/cop/rspec/describe_method.rb +2 -2
- data/lib/rubocop/cop/rspec/described_class.rb +1 -2
- data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -2
- data/lib/rubocop/cop/rspec/dialect.rb +1 -1
- data/lib/rubocop/cop/rspec/empty_example_group.rb +33 -38
- data/lib/rubocop/cop/rspec/empty_hook.rb +1 -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/expect_actual.rb +2 -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/file_path.rb +1 -1
- data/lib/rubocop/cop/rspec/focus.rb +13 -7
- data/lib/rubocop/cop/rspec/hook_argument.rb +2 -4
- data/lib/rubocop/cop/rspec/hooks_before_examples.rb +2 -2
- data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -2
- data/lib/rubocop/cop/rspec/implicit_expect.rb +1 -1
- 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/it_behaves_like.rb +1 -1
- data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
- data/lib/rubocop/cop/rspec/let_before_examples.rb +2 -2
- data/lib/rubocop/cop/rspec/let_setup.rb +7 -4
- data/lib/rubocop/cop/rspec/message_spies.rb +3 -3
- 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 +20 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +2 -3
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +1 -1
- data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +3 -1
- data/lib/rubocop/cop/rspec/named_subject.rb +8 -12
- data/lib/rubocop/cop/rspec/nested_groups.rb +1 -1
- data/lib/rubocop/cop/rspec/overwriting_setup.rb +2 -1
- data/lib/rubocop/cop/rspec/pending.rb +13 -5
- data/lib/rubocop/cop/rspec/predicate_matcher.rb +3 -3
- data/lib/rubocop/cop/rspec/repeated_include_example.rb +104 -0
- data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
- data/lib/rubocop/cop/rspec/shared_context.rb +18 -11
- data/lib/rubocop/cop/rspec/shared_examples.rb +3 -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 +20 -10
- 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_cops.rb +2 -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 +1 -1
- data/lib/rubocop/rspec/example_group.rb +15 -5
- data/lib/rubocop/rspec/hook.rb +2 -6
- data/lib/rubocop/rspec/inject.rb +4 -2
- data/lib/rubocop/rspec/language.rb +144 -105
- 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 +25 -13
- 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
data/lib/rubocop-rspec.rb
CHANGED
@@ -5,26 +5,25 @@ require 'yaml'
|
|
5
5
|
|
6
6
|
require 'rubocop'
|
7
7
|
|
8
|
-
require_relative 'rubocop/rspec'
|
9
8
|
require_relative 'rubocop/rspec/version'
|
10
9
|
require_relative 'rubocop/rspec/inject'
|
11
10
|
require_relative 'rubocop/rspec/node'
|
12
|
-
require_relative 'rubocop/rspec/top_level_describe'
|
13
11
|
require_relative 'rubocop/rspec/wording'
|
14
|
-
require_relative 'rubocop/rspec/language'
|
15
12
|
require_relative 'rubocop/rspec/language/node_pattern'
|
16
|
-
require_relative 'rubocop/rspec/
|
13
|
+
require_relative 'rubocop/rspec/language'
|
14
|
+
|
15
|
+
require_relative 'rubocop/cop/rspec/mixin/top_level_group'
|
16
|
+
require_relative 'rubocop/cop/rspec/mixin/variable'
|
17
|
+
require_relative 'rubocop/cop/rspec/mixin/final_end_location'
|
18
|
+
require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
|
19
|
+
|
17
20
|
require_relative 'rubocop/rspec/concept'
|
18
21
|
require_relative 'rubocop/rspec/example_group'
|
19
22
|
require_relative 'rubocop/rspec/example'
|
20
23
|
require_relative 'rubocop/rspec/hook'
|
21
|
-
require_relative 'rubocop/rspec/variable'
|
22
24
|
require_relative 'rubocop/cop/rspec/base'
|
23
|
-
require_relative 'rubocop/cop/rspec/cop'
|
24
25
|
require_relative 'rubocop/rspec/align_let_brace'
|
25
26
|
require_relative 'rubocop/rspec/factory_bot'
|
26
|
-
require_relative 'rubocop/rspec/final_end_location'
|
27
|
-
require_relative 'rubocop/rspec/empty_line_separation'
|
28
27
|
require_relative 'rubocop/rspec/corrector/move_node'
|
29
28
|
|
30
29
|
RuboCop::RSpec::Inject.defaults!
|
@@ -27,11 +27,9 @@ module RuboCop
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def on_new_investigation
|
30
|
+
super
|
30
31
|
return if processed_source.blank?
|
31
32
|
|
32
|
-
token_aligner =
|
33
|
-
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
|
34
|
-
|
35
33
|
token_aligner.offending_tokens.each do |let|
|
36
34
|
add_offense(let.loc.begin) do |corrector|
|
37
35
|
corrector.insert_before(
|
@@ -40,6 +38,12 @@ module RuboCop
|
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def token_aligner
|
45
|
+
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :begin)
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -27,11 +27,9 @@ module RuboCop
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def on_new_investigation
|
30
|
+
super
|
30
31
|
return if processed_source.blank?
|
31
32
|
|
32
|
-
token_aligner =
|
33
|
-
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
|
34
|
-
|
35
33
|
token_aligner.offending_tokens.each do |let|
|
36
34
|
add_offense(let.loc.end) do |corrector|
|
37
35
|
corrector.insert_before(
|
@@ -40,6 +38,12 @@ module RuboCop
|
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def token_aligner
|
45
|
+
RuboCop::RSpec::AlignLetBrace.new(processed_source.ast, :end)
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -27,11 +27,11 @@ module RuboCop
|
|
27
27
|
# end
|
28
28
|
class AroundBlock < Base
|
29
29
|
MSG_NO_ARG = 'Test object should be passed to around block.'
|
30
|
-
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` '\
|
30
|
+
MSG_UNUSED_ARG = 'You should call `%<arg>s.call` ' \
|
31
31
|
'or `%<arg>s.run`.'
|
32
32
|
|
33
33
|
def_node_matcher :hook, <<-PATTERN
|
34
|
-
(block
|
34
|
+
(block (send nil? :around sym ?) (args $...) ...)
|
35
35
|
PATTERN
|
36
36
|
|
37
37
|
def_node_search :find_arg_usage, <<-PATTERN
|
@@ -4,69 +4,22 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
6
|
# @abstract parent class to RSpec cops
|
7
|
-
#
|
8
|
-
# The criteria for whether rubocop-rspec analyzes a certain ruby file
|
9
|
-
# is configured via `AllCops/RSpec`. For example, if you want to
|
10
|
-
# customize your project to scan all files within a `test/` directory
|
11
|
-
# then you could add this to your configuration:
|
12
|
-
#
|
13
|
-
# @example configuring analyzed paths
|
14
|
-
# # .rubocop.yml
|
15
|
-
# # AllCops:
|
16
|
-
# # RSpec:
|
17
|
-
# # Patterns:
|
18
|
-
# # - '_test.rb$'
|
19
|
-
# # - '(?:^|/)test/'
|
20
7
|
class Base < ::RuboCop::Cop::Base
|
21
8
|
include RuboCop::RSpec::Language
|
22
|
-
|
9
|
+
extend RuboCop::RSpec::Language::NodePattern
|
23
10
|
|
24
|
-
|
25
|
-
RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec')
|
26
|
-
|
27
|
-
DEFAULT_PATTERN_RE = Regexp.union(
|
28
|
-
DEFAULT_CONFIGURATION.fetch('Patterns')
|
29
|
-
.map(&Regexp.public_method(:new))
|
30
|
-
)
|
11
|
+
exclude_from_registry
|
31
12
|
|
32
13
|
# Invoke the original inherited hook so our cops are recognized
|
33
14
|
def self.inherited(subclass) # rubocop:disable Lint/MissingSuper
|
34
15
|
RuboCop::Cop::Base.inherited(subclass)
|
35
16
|
end
|
36
17
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def relevant_rubocop_rspec_file?(file)
|
44
|
-
rspec_pattern.match?(file)
|
45
|
-
end
|
46
|
-
|
47
|
-
def rspec_pattern
|
48
|
-
if rspec_pattern_config?
|
49
|
-
Regexp.union(rspec_pattern_config.map(&Regexp.public_method(:new)))
|
50
|
-
else
|
51
|
-
DEFAULT_PATTERN_RE
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def all_cops_config
|
56
|
-
config
|
57
|
-
.for_all_cops
|
58
|
-
end
|
59
|
-
|
60
|
-
def rspec_pattern_config?
|
61
|
-
return unless all_cops_config.key?('RSpec')
|
62
|
-
|
63
|
-
all_cops_config.fetch('RSpec').key?('Patterns')
|
64
|
-
end
|
65
|
-
|
66
|
-
def rspec_pattern_config
|
67
|
-
all_cops_config
|
68
|
-
.fetch('RSpec', DEFAULT_CONFIGURATION)
|
69
|
-
.fetch('Patterns')
|
18
|
+
# Set the config for dynamic DSL configuration-aware helpers
|
19
|
+
# that have no other means of accessing the configuration.
|
20
|
+
def on_new_investigation
|
21
|
+
super
|
22
|
+
RuboCop::RSpec::Language.config = config['RSpec']['Language']
|
70
23
|
end
|
71
24
|
end
|
72
25
|
end
|
data/lib/rubocop/cop/rspec/be.rb
CHANGED
@@ -20,10 +20,10 @@ module RuboCop
|
|
20
20
|
# expect(foo).to be(true)
|
21
21
|
#
|
22
22
|
class Be < Base
|
23
|
-
MSG =
|
23
|
+
MSG = "Don't use `be` without an argument."
|
24
24
|
|
25
25
|
def_node_matcher :be_without_args, <<-PATTERN
|
26
|
-
(send _ #
|
26
|
+
(send _ #Runners.all $(send nil? :be))
|
27
27
|
PATTERN
|
28
28
|
|
29
29
|
def on_send(node)
|
@@ -24,9 +24,9 @@ module RuboCop
|
|
24
24
|
# after(:each) { Widget.delete_all }
|
25
25
|
# end
|
26
26
|
class BeforeAfterAll < Base
|
27
|
-
MSG = 'Beware of using `%<hook>s` as it may cause state to leak '\
|
28
|
-
'between tests. If you are using `rspec-rails`, and '\
|
29
|
-
'`use_transactional_fixtures` is enabled, then records created '\
|
27
|
+
MSG = 'Beware of using `%<hook>s` as it may cause state to leak ' \
|
28
|
+
'between tests. If you are using `rspec-rails`, and ' \
|
29
|
+
'`use_transactional_fixtures` is enabled, then records created ' \
|
30
30
|
'in `%<hook>s` are not automatically rolled back.'
|
31
31
|
|
32
32
|
def_node_matcher :before_or_after_all, <<-PATTERN
|
@@ -37,13 +37,13 @@ module RuboCop
|
|
37
37
|
# Supported matchers: eq(...) / match(/regexp/) / match('regexp')
|
38
38
|
def_node_matcher :as_is_matcher, <<-PATTERN
|
39
39
|
(send
|
40
|
-
#expectation_set_on_current_path $#
|
40
|
+
#expectation_set_on_current_path $#Runners.all
|
41
41
|
${(send nil? :eq ...) (send nil? :match (regexp ...))})
|
42
42
|
PATTERN
|
43
43
|
|
44
44
|
def_node_matcher :regexp_str_matcher, <<-PATTERN
|
45
45
|
(send
|
46
|
-
#expectation_set_on_current_path $#
|
46
|
+
#expectation_set_on_current_path $#Runners.all
|
47
47
|
$(send nil? :match (str $_)))
|
48
48
|
PATTERN
|
49
49
|
|
@@ -55,8 +55,9 @@ module RuboCop
|
|
55
55
|
feature: :describe
|
56
56
|
}.freeze
|
57
57
|
|
58
|
-
def_node_matcher :capybara_speak,
|
59
|
-
|
58
|
+
def_node_matcher :capybara_speak, <<-PATTERN
|
59
|
+
{#{MAP.keys.map(&:inspect).join(' ')}}
|
60
|
+
PATTERN
|
60
61
|
|
61
62
|
def_node_matcher :spec?, <<-PATTERN
|
62
63
|
(block
|
@@ -5,6 +5,19 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Check that the first argument to the top-level describe is a constant.
|
7
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
|
20
|
+
#
|
8
21
|
# @example
|
9
22
|
# # bad
|
10
23
|
# describe 'Do something' do
|
@@ -22,41 +35,47 @@ module RuboCop
|
|
22
35
|
# describe "A feature example", type: :feature do
|
23
36
|
# end
|
24
37
|
class DescribeClass < Base
|
25
|
-
include
|
38
|
+
include TopLevelGroup
|
26
39
|
|
27
|
-
MSG = 'The first argument to describe should be '\
|
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
|
-
(sym :type)
|
33
|
-
(sym { :channel :controller :helper :job :mailer :model :request
|
34
|
-
:routing :view :feature :system :mailbox })
|
35
|
-
)
|
36
|
-
PATTERN
|
37
|
-
|
38
|
-
def_node_matcher :example_group_with_rails_metadata?, <<~PATTERN
|
39
|
-
(send #rspec? :describe ... (hash <#rails_metadata? ...>))
|
43
|
+
def_node_matcher :example_group_with_ignored_metadata?, <<~PATTERN
|
44
|
+
(send #rspec? :describe ... (hash <#ignored_metadata? ...>))
|
40
45
|
PATTERN
|
41
46
|
|
42
47
|
def_node_matcher :not_a_const_described, <<~PATTERN
|
43
48
|
(send #rspec? :describe $[!const !#string_constant?] ...)
|
44
49
|
PATTERN
|
45
50
|
|
46
|
-
|
47
|
-
|
51
|
+
def_node_matcher :sym_pair, <<~PATTERN
|
52
|
+
(pair $sym $sym)
|
53
|
+
PATTERN
|
48
54
|
|
49
|
-
|
55
|
+
def on_top_level_group(node)
|
56
|
+
return if example_group_with_ignored_metadata?(node.send_node)
|
57
|
+
|
58
|
+
not_a_const_described(node.send_node) do |described|
|
50
59
|
add_offense(described)
|
51
60
|
end
|
52
61
|
end
|
53
62
|
|
54
63
|
private
|
55
64
|
|
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
|
+
|
56
71
|
def string_constant?(described)
|
57
72
|
described.str_type? &&
|
58
73
|
described.value.match?(/^(?:(?:::)?[A-Z]\w*)+$/)
|
59
74
|
end
|
75
|
+
|
76
|
+
def ignored_metadata
|
77
|
+
cop_config['IgnoredMetadata'] || {}
|
78
|
+
end
|
60
79
|
end
|
61
80
|
end
|
62
81
|
end
|
@@ -17,9 +17,9 @@ module RuboCop
|
|
17
17
|
# describe MyClass, '.my_class_method' do
|
18
18
|
# end
|
19
19
|
class DescribeMethod < Base
|
20
|
-
include
|
20
|
+
include TopLevelGroup
|
21
21
|
|
22
|
-
MSG = 'The second argument to describe should be the method '\
|
22
|
+
MSG = 'The second argument to describe should be the method ' \
|
23
23
|
"being tested. '#instance' or '.class'."
|
24
24
|
|
25
25
|
def_node_matcher :second_argument, <<~PATTERN
|
@@ -65,8 +65,7 @@ module RuboCop
|
|
65
65
|
(block (send (const nil? {:Class :Module :Struct}) :new ...) ...)
|
66
66
|
PATTERN
|
67
67
|
|
68
|
-
def_node_matcher :rspec_block?,
|
69
|
-
RuboCop::RSpec::Language::ALL.block_pattern
|
68
|
+
def_node_matcher :rspec_block?, block_pattern('#ALL.all')
|
70
69
|
|
71
70
|
def_node_matcher :scope_changing_syntax?, '{def class module}'
|
72
71
|
|
@@ -22,8 +22,7 @@ module RuboCop
|
|
22
22
|
class DescribedClassModuleWrapping < Base
|
23
23
|
MSG = 'Avoid opening modules and defining specs within them.'
|
24
24
|
|
25
|
-
def_node_search :find_rspec_blocks,
|
26
|
-
ExampleGroups::ALL.block_pattern
|
25
|
+
def_node_search :find_rspec_blocks, block_pattern('#ExampleGroups.all')
|
27
26
|
|
28
27
|
def on_module(node)
|
29
28
|
find_rspec_blocks(node) do
|
@@ -5,8 +5,6 @@ module RuboCop
|
|
5
5
|
module RSpec
|
6
6
|
# Checks if an example group does not include any tests.
|
7
7
|
#
|
8
|
-
# This cop is configurable using the `CustomIncludeMethods` option
|
9
|
-
#
|
10
8
|
# @example usage
|
11
9
|
#
|
12
10
|
# # bad
|
@@ -33,30 +31,10 @@ module RuboCop
|
|
33
31
|
# end
|
34
32
|
# end
|
35
33
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# # .rubocop.yml
|
39
|
-
# # RSpec/EmptyExampleGroup:
|
40
|
-
# # CustomIncludeMethods:
|
41
|
-
# # - include_tests
|
42
|
-
#
|
43
|
-
# # spec_helper.rb
|
44
|
-
# RSpec.configure do |config|
|
45
|
-
# config.alias_it_behaves_like_to(:include_tests)
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# # bacon_spec.rb
|
34
|
+
# # good
|
49
35
|
# describe Bacon do
|
50
|
-
#
|
51
|
-
# let(:chunkiness) { false }
|
52
|
-
#
|
53
|
-
# context 'extra chunky' do # not flagged by rubocop
|
54
|
-
# let(:chunkiness) { true }
|
55
|
-
#
|
56
|
-
# include_tests 'shared tests'
|
57
|
-
# end
|
36
|
+
# pending 'will add tests later'
|
58
37
|
# end
|
59
|
-
#
|
60
38
|
class EmptyExampleGroup < Base
|
61
39
|
MSG = 'Empty example group detected.'
|
62
40
|
|
@@ -71,7 +49,7 @@ module RuboCop
|
|
71
49
|
# @param node [RuboCop::AST::Node]
|
72
50
|
# @yield [RuboCop::AST::Node] example group body
|
73
51
|
def_node_matcher :example_group_body, <<~PATTERN
|
74
|
-
(block #{ExampleGroups
|
52
|
+
(block #{send_pattern('#ExampleGroups.all')} args $_)
|
75
53
|
PATTERN
|
76
54
|
|
77
55
|
# @!method example_or_group_or_include?(node)
|
@@ -83,16 +61,17 @@ module RuboCop
|
|
83
61
|
# it_behaves_like 'an animal'
|
84
62
|
# it_behaves_like('a cat') { let(:food) { 'milk' } }
|
85
63
|
# it_has_root_access
|
64
|
+
# skip
|
65
|
+
# it 'will be implemented later'
|
86
66
|
#
|
87
67
|
# @param node [RuboCop::AST::Node]
|
88
68
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
89
69
|
def_node_matcher :example_or_group_or_include?, <<~PATTERN
|
90
70
|
{
|
91
|
-
#{
|
92
|
-
|
93
|
-
|
94
|
-
#{Includes
|
95
|
-
(send nil? #custom_include? ...)
|
71
|
+
#{block_pattern(
|
72
|
+
'{#Examples.all #ExampleGroups.all #Includes.all}'
|
73
|
+
)}
|
74
|
+
#{send_pattern('{#Examples.all #Includes.all}')}
|
96
75
|
}
|
97
76
|
PATTERN
|
98
77
|
|
@@ -112,7 +91,7 @@ module RuboCop
|
|
112
91
|
# @param node [RuboCop::AST::Node]
|
113
92
|
# @return [Array<RuboCop::AST::Node>] matching nodes
|
114
93
|
def_node_matcher :examples_inside_block?, <<~PATTERN
|
115
|
-
(block !#{Hooks
|
94
|
+
(block !#{send_pattern('#Hooks.all')} _ #examples?)
|
116
95
|
PATTERN
|
117
96
|
|
118
97
|
# @!method examples_directly_or_in_block?(node)
|
@@ -152,21 +131,37 @@ module RuboCop
|
|
152
131
|
PATTERN
|
153
132
|
|
154
133
|
def on_block(node)
|
134
|
+
return if node.each_ancestor(:def, :defs).any?
|
135
|
+
return if node.each_ancestor(:block).any? { |block| example?(block) }
|
136
|
+
|
155
137
|
example_group_body(node) do |body|
|
156
|
-
add_offense(node.send_node)
|
138
|
+
add_offense(node.send_node) if offensive?(body)
|
157
139
|
end
|
158
140
|
end
|
159
141
|
|
160
142
|
private
|
161
143
|
|
162
|
-
def
|
163
|
-
|
144
|
+
def offensive?(body)
|
145
|
+
return true unless body
|
146
|
+
return false if conditionals_with_examples?(body)
|
147
|
+
|
148
|
+
if body.if_type?
|
149
|
+
!examples_in_branches?(body)
|
150
|
+
else
|
151
|
+
!examples?(body)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def conditionals_with_examples?(body)
|
156
|
+
return unless body.begin_type?
|
157
|
+
|
158
|
+
body.each_descendant(:if).any? do |if_node|
|
159
|
+
examples_in_branches?(if_node)
|
160
|
+
end
|
164
161
|
end
|
165
162
|
|
166
|
-
def
|
167
|
-
|
168
|
-
.fetch('CustomIncludeMethods', [])
|
169
|
-
.map(&:to_sym)
|
163
|
+
def examples_in_branches?(if_node)
|
164
|
+
if_node.branches.any? { |branch| examples?(branch) }
|
170
165
|
end
|
171
166
|
end
|
172
167
|
end
|