rubocop-rspec 2.6.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Check for expectations where `be(...)` can replace `eq(...)`.
7
+ #
8
+ # The `be` matcher compares by identity while the `eq` matcher compares
9
+ # using `==`. Booleans and nil can be compared by identity and therefore
10
+ # the `be` matcher is preferable as it is a more strict test.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # expect(foo).to eq(true)
16
+ # expect(foo).to eq(false)
17
+ # expect(foo).to eq(nil)
18
+ #
19
+ # # good
20
+ # expect(foo).to be(true)
21
+ # expect(foo).to be(false)
22
+ # expect(foo).to be(nil)
23
+ #
24
+ class BeEq < Base
25
+ extend AutoCorrector
26
+
27
+ MSG = 'Prefer `be` over `eq`.'
28
+ RESTRICT_ON_SEND = %i[eq].freeze
29
+
30
+ # @!method eq_type_with_identity?(node)
31
+ def_node_matcher :eq_type_with_identity?, <<-PATTERN
32
+ (send nil? :eq {true false nil})
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ return unless eq_type_with_identity?(node)
37
+
38
+ add_offense(node.loc.selector) do |corrector|
39
+ corrector.replace(node.loc.selector, 'be')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -43,7 +43,7 @@ module RuboCop
43
43
 
44
44
  # @!method eql_type_with_identity(node)
45
45
  def_node_matcher :eql_type_with_identity, <<-PATTERN
46
- (send _ :to $(send nil? :eql {true false int float sym nil_type?}))
46
+ (send _ :to $(send nil? :eql {true false int float sym nil}))
47
47
  PATTERN
48
48
 
49
49
  def on_send(node)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Check that `be_nil` is used instead of `be(nil)`.
7
+ #
8
+ # RSpec has a built-in `be_nil` matcher specifically for expecting `nil`.
9
+ # For consistent specs, we recommend using that instead of `be(nil)`.
10
+ #
11
+ # @example
12
+ #
13
+ # # bad
14
+ # expect(foo).to be(nil)
15
+ #
16
+ # # good
17
+ # expect(foo).to be_nil
18
+ #
19
+ class BeNil < Base
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Prefer `be_nil` over `be(nil)`.'
23
+ RESTRICT_ON_SEND = %i[be].freeze
24
+
25
+ # @!method nil_value_expectation?(node)
26
+ def_node_matcher :nil_value_expectation?, <<-PATTERN
27
+ (send nil? :be nil)
28
+ PATTERN
29
+
30
+ def on_send(node)
31
+ return unless nil_value_expectation?(node)
32
+
33
+ add_offense(node) do |corrector|
34
+ corrector.replace(node.loc.expression, 'be_nil')
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -6,13 +6,13 @@ module RuboCop
6
6
  module Capybara
7
7
  # Checks that no expectations are set on Capybara's `current_path`.
8
8
  #
9
- # The `have_current_path` matcher (https://www.rubydoc.info/github/
10
- # teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-
11
- # instance_method) should be used on `page` to set expectations on
12
- # Capybara's current path, since it uses Capybara's waiting
13
- # functionality (https://github.com/teamcapybara/capybara/blob/master/
14
- # README.md#asynchronous-javascript-ajax-and-friends) which ensures that
15
- # preceding actions (like `click_link`) have completed.
9
+ # The
10
+ # https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method[`have_current_path` matcher]
11
+ # should be used on `page` to set expectations on Capybara's
12
+ # current path, since it uses
13
+ # https://github.com/teamcapybara/capybara/blob/master/README.md#asynchronous-javascript-ajax-and-friends[Capybara's waiting functionality]
14
+ # which ensures that preceding actions (like `click_link`) have
15
+ # completed.
16
16
  #
17
17
  # @example
18
18
  # # bad
@@ -42,6 +42,7 @@ module RuboCop
42
42
  # end
43
43
  class FeatureMethods < Base
44
44
  extend AutoCorrector
45
+ include InsideExampleGroup
45
46
 
46
47
  MSG = 'Use `%<replacement>s` instead of `%<method>s`.'
47
48
 
@@ -60,13 +61,6 @@ module RuboCop
60
61
  {#{MAP.keys.map(&:inspect).join(' ')}}
61
62
  PATTERN
62
63
 
63
- # @!method spec?(node)
64
- def_node_matcher :spec?, <<-PATTERN
65
- (block
66
- (send #rspec? {:describe :feature} ...)
67
- ...)
68
- PATTERN
69
-
70
64
  # @!method feature_method(node)
71
65
  def_node_matcher :feature_method, <<-PATTERN
72
66
  (block
@@ -75,7 +69,7 @@ module RuboCop
75
69
  PATTERN
76
70
 
77
71
  def on_block(node)
78
- return unless inside_spec?(node)
72
+ return unless inside_example_group?(node)
79
73
 
80
74
  feature_method(node) do |send_node, match|
81
75
  next if enabled?(match)
@@ -93,21 +87,6 @@ module RuboCop
93
87
 
94
88
  private
95
89
 
96
- def inside_spec?(node)
97
- return spec?(node) if root_node?(node)
98
-
99
- root = node.ancestors.find { |parent| root_node?(parent) }
100
- spec?(root)
101
- end
102
-
103
- def root_node?(node)
104
- node.parent.nil? || root_with_siblings?(node.parent)
105
- end
106
-
107
- def root_with_siblings?(node)
108
- node.begin_type? && node.parent.nil?
109
- end
110
-
111
90
  def enabled?(method_name)
112
91
  enabled_methods.include?(method_name)
113
92
  end
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
6
  module Capybara
7
- # Checks for boolean visibility in capybara finders.
7
+ # Checks for boolean visibility in Capybara finders.
8
8
  #
9
9
  # Capybara lets you find elements that match a certain visibility using
10
10
  # the `:visible` option. `:visible` accepts both boolean and symbols as
@@ -12,7 +12,8 @@ module RuboCop
12
12
  # false` does not find just invisible elements, but both visible and
13
13
  # invisible elements. For expressiveness and clarity, use one of the
14
14
  # symbol values, `:all`, `:hidden` or `:visible`.
15
- # (https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all)
15
+ # Read more in
16
+ # https://www.rubydoc.info/gems/capybara/Capybara%2FNode%2FFinders:all[the documentation].
16
17
  #
17
18
  # @example
18
19
  #
@@ -17,24 +17,18 @@ module RuboCop
17
17
  class EmptyLineAfterSubject < Base
18
18
  extend AutoCorrector
19
19
  include EmptyLineSeparation
20
+ include InsideExampleGroup
20
21
 
21
22
  MSG = 'Add an empty line after `%<subject>s`.'
22
23
 
23
24
  def on_block(node)
24
- return unless subject?(node) && !in_spec_block?(node)
25
+ return unless subject?(node)
26
+ return unless inside_example_group?(node)
25
27
 
26
28
  missing_separating_line_offense(node) do |method|
27
29
  format(MSG, subject: method)
28
30
  end
29
31
  end
30
-
31
- private
32
-
33
- def in_spec_block?(node)
34
- node.each_ancestor(:block).any? do |ancestor|
35
- Examples.all(ancestor.method_name)
36
- end
37
- end
38
32
  end
39
33
  end
40
34
  end
@@ -27,6 +27,7 @@ module RuboCop
27
27
  class CreateList < Base
28
28
  extend AutoCorrector
29
29
  include ConfigurableEnforcedStyle
30
+ include RuboCop::RSpec::FactoryBot::Language
30
31
 
31
32
  MSG_CREATE_LIST = 'Prefer create_list.'
32
33
  MSG_N_TIMES = 'Prefer %<number>s.times.'
@@ -43,12 +44,12 @@ module RuboCop
43
44
 
44
45
  # @!method factory_call(node)
45
46
  def_node_matcher :factory_call, <<-PATTERN
46
- (send ${(const nil? {:FactoryGirl :FactoryBot}) nil?} :create (sym $_) $...)
47
+ (send ${nil? #factory_bot?} :create (sym $_) $...)
47
48
  PATTERN
48
49
 
49
50
  # @!method factory_list_call(node)
50
51
  def_node_matcher :factory_list_call, <<-PATTERN
51
- (send {(const nil? {:FactoryGirl :FactoryBot}) nil?} :create_list (sym _) (int $_) ...)
52
+ (send {nil? #factory_bot?} :create_list (sym _) (int $_) ...)
52
53
  PATTERN
53
54
 
54
55
  def on_block(node)
@@ -160,7 +161,7 @@ module RuboCop
160
161
  def call_with_block_replacement(node)
161
162
  block = node.body
162
163
  arguments = build_arguments(block, node.receiver.source)
163
- replacement = format_receiver(block.send_node.receiver)
164
+ replacement = format_receiver(block.receiver)
164
165
  replacement += format_method_call(block, 'create_list', arguments)
165
166
  replacement += format_block(block)
166
167
  replacement
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ module FactoryBot
7
+ # Use shorthands from `FactoryBot::Syntax::Methods` in your specs.
8
+ #
9
+ # @safety
10
+ # The auto-correction is marked as unsafe because the cop
11
+ # cannot verify whether you already include
12
+ # `FactoryBot::Syntax::Methods` in your test suite.
13
+ #
14
+ # If you're using Rails, add the following configuration to
15
+ # `spec/support/factory_bot.rb` and be sure to require that file in
16
+ # `rails_helper.rb`:
17
+ #
18
+ # [source,ruby]
19
+ # ----
20
+ # RSpec.configure do |config|
21
+ # config.include FactoryBot::Syntax::Methods
22
+ # end
23
+ # ----
24
+ #
25
+ # If you're not using Rails:
26
+ #
27
+ # [source,ruby]
28
+ # ----
29
+ # RSpec.configure do |config|
30
+ # config.include FactoryBot::Syntax::Methods
31
+ #
32
+ # config.before(:suite) do
33
+ # FactoryBot.find_definitions
34
+ # end
35
+ # end
36
+ # ----
37
+ #
38
+ # @example
39
+ # # bad
40
+ # FactoryBot.create(:bar)
41
+ # FactoryBot.build(:bar)
42
+ # FactoryBot.attributes_for(:bar)
43
+ #
44
+ # # good
45
+ # create(:bar)
46
+ # build(:bar)
47
+ # attributes_for(:bar)
48
+ #
49
+ class SyntaxMethods < Base
50
+ extend AutoCorrector
51
+ include InsideExampleGroup
52
+ include RangeHelp
53
+ include RuboCop::RSpec::FactoryBot::Language
54
+
55
+ MSG = 'Use `%<method>s` from `FactoryBot::Syntax::Methods`.'
56
+
57
+ RESTRICT_ON_SEND = %i[
58
+ attributes_for
59
+ attributes_for_list
60
+ attributes_for_pair
61
+ build
62
+ build_list
63
+ build_pair
64
+ build_stubbed
65
+ build_stubbed_list
66
+ build_stubbed_pair
67
+ create
68
+ create_list
69
+ create_pair
70
+ generate
71
+ generate_list
72
+ null
73
+ null_list
74
+ null_pair
75
+ ].to_set.freeze
76
+
77
+ def on_send(node)
78
+ return unless factory_bot?(node.receiver)
79
+ return unless inside_example_group?(node)
80
+
81
+ message = format(MSG, method: node.method_name)
82
+
83
+ add_offense(crime_scene(node), message: message) do |corrector|
84
+ corrector.remove(offense(node))
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def crime_scene(node)
91
+ range_between(
92
+ node.loc.expression.begin_pos,
93
+ node.loc.selector.end_pos
94
+ )
95
+ end
96
+
97
+ def offense(node)
98
+ range_between(
99
+ node.loc.expression.begin_pos,
100
+ node.loc.selector.begin_pos
101
+ )
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -33,11 +33,13 @@ module RuboCop
33
33
  #
34
34
  class LeadingSubject < Base
35
35
  extend AutoCorrector
36
+ include InsideExampleGroup
36
37
 
37
38
  MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
38
39
 
39
40
  def on_block(node)
40
- return unless subject?(node) && !in_spec_block?(node)
41
+ return unless subject?(node)
42
+ return unless inside_example_group?(node)
41
43
 
42
44
  check_previous_nodes(node)
43
45
  end
@@ -78,12 +80,6 @@ module RuboCop
78
80
  spec_group?(node) ||
79
81
  include?(node)
80
82
  end
81
-
82
- def in_spec_block?(node)
83
- node.each_ancestor(:block).any? do |ancestor|
84
- example?(ancestor)
85
- end
86
- end
87
83
  end
88
84
  end
89
85
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RSpec
6
+ # Helps you identify whether a given node
7
+ # is within an example group or not.
8
+ module InsideExampleGroup
9
+ private
10
+
11
+ def inside_example_group?(node)
12
+ return spec_group?(node) if example_group_root?(node)
13
+
14
+ root = node.ancestors.find { |parent| example_group_root?(parent) }
15
+
16
+ spec_group?(root)
17
+ end
18
+
19
+ def example_group_root?(node)
20
+ node.parent.nil? || example_group_root_with_siblings?(node.parent)
21
+ end
22
+
23
+ def example_group_root_with_siblings?(node)
24
+ node.begin_type? && node.parent.nil?
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -7,6 +7,9 @@ module RuboCop
7
7
  module RSpec
8
8
  # Checks for stubbed test subjects.
9
9
  #
10
+ # Checks nested subject stubs for innermost subject definition
11
+ # when subject is also defined in parent example groups.
12
+ #
10
13
  # @see https://robots.thoughtbot.com/don-t-stub-the-system-under-test
11
14
  # @see https://samphippen.com/introducing-rspec-smells-and-where-to-find-them#smell-1-stubject
12
15
  # @see https://github.com/rubocop-hq/rspec-style-guide#dont-stub-subject
@@ -22,6 +25,20 @@ module RuboCop
22
25
  # end
23
26
  # end
24
27
  #
28
+ # # bad
29
+ # describe Article do
30
+ # subject(:foo) { Article.new }
31
+ #
32
+ # context 'nested subject' do
33
+ # subject(:article) { Article.new }
34
+ #
35
+ # it 'indicates that the author is unknown' do
36
+ # allow(article).to receive(:author).and_return(nil)
37
+ # expect(article.description).to include('by an unknown author')
38
+ # end
39
+ # end
40
+ # end
41
+ #
25
42
  # # good
26
43
  # describe Article do
27
44
  # subject(:article) { Article.new(author: nil) }
@@ -36,27 +53,35 @@ module RuboCop
36
53
 
37
54
  MSG = 'Do not stub methods of the object under test.'
38
55
 
39
- # @!method subject(node)
56
+ # @!method subject?(node)
40
57
  # Find a named or unnamed subject definition
41
58
  #
42
59
  # @example anonymous subject
43
- # subject(parse('subject { foo }').ast) do |name|
60
+ # subject?(parse('subject { foo }').ast) do |name|
44
61
  # name # => :subject
45
62
  # end
46
63
  #
47
64
  # @example named subject
48
- # subject(parse('subject(:thing) { foo }').ast) do |name|
65
+ # subject?(parse('subject(:thing) { foo }').ast) do |name|
49
66
  # name # => :thing
50
67
  # end
51
68
  #
52
69
  # @param node [RuboCop::AST::Node]
53
70
  #
54
71
  # @yield [Symbol] subject name
55
- def_node_matcher :subject, <<-PATTERN
56
- (block
57
- (send nil?
58
- {:subject (sym $_) | $:subject}
59
- ) args ...)
72
+ def_node_matcher :subject?, <<-PATTERN
73
+ (block
74
+ (send nil?
75
+ {:subject (sym $_) | $:subject}
76
+ ) args ...)
77
+ PATTERN
78
+
79
+ # @!method let?(node)
80
+ # Find a memoized helper
81
+ def_node_matcher :let?, <<-PATTERN
82
+ (block
83
+ (send nil? :let (sym $_)
84
+ ) args ...)
60
85
  PATTERN
61
86
 
62
87
  # @!method message_expectation?(node, method_name)
@@ -73,7 +98,7 @@ module RuboCop
73
98
  def_node_matcher :message_expectation?, <<-PATTERN
74
99
  (send
75
100
  {
76
- (send nil? { :expect :allow } (send nil? {% :subject}))
101
+ (send nil? { :expect :allow } (send nil? %))
77
102
  (send nil? :is_expected)
78
103
  }
79
104
  #Runners.all
@@ -89,7 +114,8 @@ module RuboCop
89
114
  PATTERN
90
115
 
91
116
  def on_top_level_group(node)
92
- @explicit_subjects = find_all_explicit_subjects(node)
117
+ @explicit_subjects = find_all_explicit(node, &method(:subject?))
118
+ @subject_overrides = find_all_explicit(node, &method(:let?))
93
119
 
94
120
  find_subject_expectations(node) do |stub|
95
121
  add_offense(stub)
@@ -98,12 +124,12 @@ module RuboCop
98
124
 
99
125
  private
100
126
 
101
- def find_all_explicit_subjects(node)
127
+ def find_all_explicit(node)
102
128
  node.each_descendant(:block).with_object({}) do |child, h|
103
- name = subject(child)
129
+ name = yield(child)
104
130
  next unless name
105
131
 
106
- outer_example_group = child.each_ancestor.find do |a|
132
+ outer_example_group = child.each_ancestor(:block).find do |a|
107
133
  example_group?(a)
108
134
  end
109
135
 
@@ -113,14 +139,14 @@ module RuboCop
113
139
  end
114
140
 
115
141
  def find_subject_expectations(node, subject_names = [], &block)
116
- subject_names = @explicit_subjects[node] if @explicit_subjects[node]
142
+ subject_names = [*subject_names, *@explicit_subjects[node]]
143
+ subject_names -= @subject_overrides[node] if @subject_overrides[node]
117
144
 
118
- expectation_detected = (subject_names + [:subject]).any? do |name|
119
- message_expectation?(node, name)
120
- end
145
+ names = Set[*subject_names, :subject]
146
+ expectation_detected = message_expectation?(node, names)
121
147
  return yield(node) if expectation_detected
122
148
 
123
- node.each_child_node do |child|
149
+ node.each_child_node(:send, :def, :block, :begin) do |child|
124
150
  find_subject_expectations(child, subject_names, &block)
125
151
  end
126
152
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # allow(foo).to receive(:bar) { |&block| block.call(1) }
11
11
  #
12
12
  # # good
13
- # expect(foo).to be(:bar).and_yield(1)
13
+ # expect(foo).to receive(:bar).and_yield(1)
14
14
  class Yield < Base
15
15
  extend AutoCorrector
16
16
  include RangeHelp
@@ -7,6 +7,7 @@ require_relative 'rspec/capybara/visibility_matcher'
7
7
  require_relative 'rspec/factory_bot/attribute_defined_statically'
8
8
  require_relative 'rspec/factory_bot/create_list'
9
9
  require_relative 'rspec/factory_bot/factory_class_name'
10
+ require_relative 'rspec/factory_bot/syntax_methods'
10
11
 
11
12
  require_relative 'rspec/rails/avoid_setup_hook'
12
13
  begin
@@ -20,7 +21,9 @@ require_relative 'rspec/align_right_let_brace'
20
21
  require_relative 'rspec/any_instance'
21
22
  require_relative 'rspec/around_block'
22
23
  require_relative 'rspec/be'
24
+ require_relative 'rspec/be_eq'
23
25
  require_relative 'rspec/be_eql'
26
+ require_relative 'rspec/be_nil'
24
27
  require_relative 'rspec/before_after_all'
25
28
  require_relative 'rspec/context_method'
26
29
  require_relative 'rspec/context_wording'
@@ -8,7 +8,7 @@ module RuboCop
8
8
  class ConfigFormatter
9
9
  EXTENSION_ROOT_DEPARTMENT = %r{^(RSpec/)}.freeze
10
10
  SUBDEPARTMENTS = %(RSpec/Capybara RSpec/FactoryBot RSpec/Rails)
11
- STYLE_GUIDE_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/'
11
+ COP_DOC_BASE_URL = 'https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/'
12
12
 
13
13
  def initialize(config, descriptions)
14
14
  @config = config
@@ -27,9 +27,8 @@ module RuboCop
27
27
  cops.each_with_object(config.dup) do |cop, unified|
28
28
  next if SUBDEPARTMENTS.include?(cop)
29
29
 
30
- unified[cop] = config.fetch(cop)
31
- .merge(descriptions.fetch(cop))
32
- .merge('StyleGuide' => STYLE_GUIDE_BASE_URL + cop.sub('RSpec/', ''))
30
+ unified[cop].merge!(descriptions.fetch(cop))
31
+ unified[cop]['Reference'] = COP_DOC_BASE_URL + cop.sub('RSpec/', '')
33
32
  end
34
33
  end
35
34
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RSpec
5
+ module FactoryBot
6
+ # Contains node matchers for common FactoryBot DSL.
7
+ module Language
8
+ extend RuboCop::NodePattern::Macros
9
+
10
+ # @!method factory_bot?(node)
11
+ def_node_matcher :factory_bot?, <<~PATTERN
12
+ (const {nil? cbase} {:FactoryGirl :FactoryBot})
13
+ PATTERN
14
+ end
15
+ end
16
+ end
17
+ end
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module RSpec
5
5
  # Version information for the RSpec RuboCop plugin.
6
6
  module Version
7
- STRING = '2.6.0'
7
+ STRING = '2.9.0'
8
8
  end
9
9
  end
10
10
  end
data/lib/rubocop-rspec.rb CHANGED
@@ -12,11 +12,14 @@ require_relative 'rubocop/rspec/wording'
12
12
  require_relative 'rubocop/rspec/language/node_pattern'
13
13
  require_relative 'rubocop/rspec/language'
14
14
 
15
+ require_relative 'rubocop/rspec/factory_bot/language'
16
+
15
17
  require_relative 'rubocop/cop/rspec/mixin/top_level_group'
16
18
  require_relative 'rubocop/cop/rspec/mixin/variable'
17
19
  require_relative 'rubocop/cop/rspec/mixin/final_end_location'
18
20
  require_relative 'rubocop/cop/rspec/mixin/comments_help'
19
21
  require_relative 'rubocop/cop/rspec/mixin/empty_line_separation'
22
+ require_relative 'rubocop/cop/rspec/mixin/inside_example_group'
20
23
 
21
24
  require_relative 'rubocop/rspec/concept'
22
25
  require_relative 'rubocop/rspec/example_group'
@@ -31,8 +34,8 @@ RuboCop::RSpec::Inject.defaults!
31
34
 
32
35
  require_relative 'rubocop/cop/rspec_cops'
33
36
 
34
- # We have to register our autocorrect incompatibilies in RuboCop's cops as well
35
- # so we do not hit infinite loops
37
+ # We have to register our autocorrect incompatibilities in RuboCop's cops
38
+ # as well so we do not hit infinite loops
36
39
 
37
40
  module RuboCop
38
41
  module Cop