rubocop 1.7.0 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -3
  4. data/config/default.yml +137 -31
  5. data/config/obsoletion.yml +4 -0
  6. data/lib/rubocop.rb +14 -1
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  8. data/lib/rubocop/comment_config.rb +6 -6
  9. data/lib/rubocop/config.rb +5 -2
  10. data/lib/rubocop/config_loader.rb +7 -14
  11. data/lib/rubocop/config_store.rb +12 -1
  12. data/lib/rubocop/cop/base.rb +2 -1
  13. data/lib/rubocop/cop/exclude_limit.rb +26 -0
  14. data/lib/rubocop/cop/gemspec/date_assignment.rb +56 -0
  15. data/lib/rubocop/cop/generator.rb +1 -3
  16. data/lib/rubocop/cop/internal_affairs.rb +5 -1
  17. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  18. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  19. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  20. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  21. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  22. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +38 -18
  23. data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
  24. data/lib/rubocop/cop/layout/line_length.rb +2 -1
  25. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +26 -0
  26. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -2
  27. data/lib/rubocop/cop/layout/space_before_brackets.rb +19 -16
  28. data/lib/rubocop/cop/lint/debugger.rb +58 -14
  29. data/lib/rubocop/cop/lint/deprecated_constants.rb +80 -0
  30. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +13 -4
  31. data/lib/rubocop/cop/lint/duplicate_require.rb +2 -2
  32. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  33. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +44 -0
  34. data/lib/rubocop/cop/lint/multiple_comparison.rb +4 -4
  35. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +10 -6
  36. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  37. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  38. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  39. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +2 -1
  40. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +50 -0
  41. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +5 -3
  42. data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
  43. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  44. data/lib/rubocop/cop/message_annotator.rb +4 -1
  45. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
  46. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  47. data/lib/rubocop/cop/mixin/allowed_identifiers.rb +18 -0
  48. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  49. data/lib/rubocop/cop/mixin/code_length.rb +3 -1
  50. data/lib/rubocop/cop/mixin/comments_help.rb +1 -11
  51. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
  52. data/lib/rubocop/cop/mixin/first_element_line_break.rb +1 -1
  53. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
  54. data/lib/rubocop/cop/mixin/preferred_delimiters.rb +2 -2
  55. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +5 -1
  56. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  57. data/lib/rubocop/cop/naming/variable_name.rb +2 -0
  58. data/lib/rubocop/cop/naming/variable_number.rb +2 -9
  59. data/lib/rubocop/cop/registry.rb +1 -1
  60. data/lib/rubocop/cop/severity.rb +3 -3
  61. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  62. data/lib/rubocop/cop/style/constant_visibility.rb +27 -0
  63. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  64. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  65. data/lib/rubocop/cop/style/empty_literal.rb +6 -2
  66. data/lib/rubocop/cop/style/endless_method.rb +102 -0
  67. data/lib/rubocop/cop/style/eval_with_location.rb +138 -49
  68. data/lib/rubocop/cop/style/explicit_block_argument.rb +11 -1
  69. data/lib/rubocop/cop/style/exponential_notation.rb +6 -7
  70. data/lib/rubocop/cop/style/float_division.rb +3 -0
  71. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  72. data/lib/rubocop/cop/style/hash_conversion.rb +81 -0
  73. data/lib/rubocop/cop/style/hash_like_case.rb +2 -1
  74. data/lib/rubocop/cop/style/if_inside_else.rb +22 -10
  75. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
  76. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +4 -0
  77. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +4 -0
  78. data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
  79. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  80. data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
  81. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  82. data/lib/rubocop/cop/style/raise_args.rb +3 -2
  83. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  84. data/lib/rubocop/cop/style/single_line_methods.rb +32 -2
  85. data/lib/rubocop/cop/style/sole_nested_conditional.rb +29 -5
  86. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  87. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  88. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  89. data/lib/rubocop/cop/style/while_until_modifier.rb +2 -4
  90. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  91. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  92. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
  93. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  94. data/lib/rubocop/magic_comment.rb +30 -1
  95. data/lib/rubocop/options.rb +1 -1
  96. data/lib/rubocop/rspec/expect_offense.rb +5 -2
  97. data/lib/rubocop/runner.rb +1 -0
  98. data/lib/rubocop/target_ruby.rb +47 -11
  99. data/lib/rubocop/version.rb +2 -2
  100. metadata +24 -7
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # This cop checks for redundant `subject(:cop) { described_class.new }`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # RSpec.describe RuboCop::Cop::Department::Foo do
11
+ # subject(:cop) { described_class.new(config) }
12
+ # end
13
+ #
14
+ # # good
15
+ # RSpec.describe RuboCop::Cop::Department::Foo, :config do
16
+ # end
17
+ #
18
+ class RedundantDescribedClassAsSubject < Base
19
+ include RangeHelp
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Remove the redundant `subject`%<additional_message>s.'
23
+
24
+ def_node_matcher :described_class_subject?, <<~PATTERN
25
+ (block
26
+ (send nil? :subject
27
+ (sym :cop))
28
+ (args)
29
+ (send
30
+ (send nil? :described_class) :new
31
+ $...))
32
+ PATTERN
33
+
34
+ def on_block(node)
35
+ return unless (described_class_arguments = described_class_subject?(node))
36
+ return if described_class_arguments.count >= 2
37
+
38
+ describe = find_describe_method_node(node)
39
+
40
+ unless (exist_config = describe.last_argument.source == ':config')
41
+ additional_message = ' and specify `:config` in `describe`'
42
+ end
43
+
44
+ message = format(MSG, additional_message: additional_message)
45
+
46
+ add_offense(node, message: message) do |corrector|
47
+ corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
48
+
49
+ corrector.insert_after(describe.last_argument, ', :config') unless exist_config
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def find_describe_method_node(block_node)
56
+ block_node.ancestors.find { |node| node.block_type? && node.method?(:describe) }.send_node
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # This cop checks that `let` is `RuboCop::Config.new` with no arguments.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # RSpec.describe RuboCop::Cop::Department::Foo, :config do
11
+ # let(:config) { RuboCop::Config.new }
12
+ # end
13
+ #
14
+ # # good
15
+ # RSpec.describe RuboCop::Cop::Department::Foo, :config do
16
+ # end
17
+ #
18
+ # RSpec.describe RuboCop::Cop::Department::Foo, :config do
19
+ # let(:config) { RuboCop::Config.new(argument) }
20
+ # end
21
+ #
22
+ class RedundantLetRuboCopConfigNew < Base
23
+ include RangeHelp
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Remove `let` that is `RuboCop::Config.new` with no arguments%<additional_message>s.'
27
+
28
+ def_node_matcher :let_rubocop_config_new?, <<~PATTERN
29
+ (block
30
+ (send nil? :let
31
+ (sym :config))
32
+ (args)
33
+ (send
34
+ (const
35
+ (const nil? :RuboCop) :Config) :new))
36
+ PATTERN
37
+
38
+ def on_block(node)
39
+ return unless let_rubocop_config_new?(node)
40
+
41
+ describe = find_describe_method_node(node)
42
+
43
+ unless (exist_config = describe.last_argument.source == ':config')
44
+ additional_message = ' and specify `:config` in `describe`'
45
+ end
46
+
47
+ message = format(MSG, additional_message: additional_message)
48
+
49
+ add_offense(node, message: message) do |corrector|
50
+ corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
51
+
52
+ corrector.insert_after(describe.last_argument, ', :config') unless exist_config
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def find_describe_method_node(block_node)
59
+ block_node.ancestors.find { |node| node.block_type? && node.method?(:describe) }.send_node
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -213,7 +213,12 @@ module RuboCop
213
213
  name = node.method_name.to_s
214
214
  category, = categories.find { |_, names| names.include?(name) }
215
215
  key = category || name
216
- visibility_key = "#{node_visibility(node)}_#{key}"
216
+ visibility_key =
217
+ if node.def_modifier?
218
+ "#{name}_methods"
219
+ else
220
+ "#{node_visibility(node)}_#{key}"
221
+ end
217
222
  expected_order.include?(visibility_key) ? visibility_key : key
218
223
  end
219
224
 
@@ -264,7 +269,7 @@ module RuboCop
264
269
 
265
270
  def source_range_with_comment(node)
266
271
  begin_pos, end_pos =
267
- if node.def_type?
272
+ if node.def_type? && !node.method?(:initialize) || node.send_type? && node.def_modifier?
268
273
  start_node = find_visibility_start(node) || node
269
274
  end_node = find_visibility_end(node) || node
270
275
  [begin_pos_with_comment(start_node),
@@ -88,7 +88,7 @@ module RuboCop
88
88
  include RangeHelp
89
89
  extend AutoCorrector
90
90
 
91
- MSG = 'Use empty lines between %<type>s definitions.'
91
+ MSG = 'Expected %<expected>s between %<type>s definitions; found %<actual>d.'
92
92
 
93
93
  def self.autocorrect_incompatible_with
94
94
  [Layout::EmptyLines]
@@ -107,19 +107,21 @@ module RuboCop
107
107
  end
108
108
 
109
109
  def check_defs(nodes)
110
- return if blank_lines_between?(*nodes)
110
+ count = blank_lines_count_between(*nodes)
111
+
112
+ return if line_count_allowed?(count)
111
113
  return if multiple_blank_lines_groups?(*nodes)
112
114
  return if nodes.all?(&:single_line?) &&
113
115
  cop_config['AllowAdjacentOneLineDefs']
114
116
 
115
117
  correction_node = nodes.last
116
118
  location = correction_node.loc.keyword.join(correction_node.loc.name)
117
- add_offense(location, message: message(correction_node)) do |corrector|
118
- autocorrect(corrector, *nodes)
119
+ add_offense(location, message: message(correction_node, count: count)) do |corrector|
120
+ autocorrect(corrector, *nodes, count)
119
121
  end
120
122
  end
121
123
 
122
- def autocorrect(corrector, prev_def, node)
124
+ def autocorrect(corrector, prev_def, node, count)
123
125
  # finds position of first newline
124
126
  end_pos = end_loc(prev_def).end_pos
125
127
  source_buffer = end_loc(prev_def).source_buffer
@@ -128,8 +130,6 @@ module RuboCop
128
130
  # Handle the case when multiple one-liners are on the same line.
129
131
  newline_pos = end_pos + 1 if newline_pos > node.source_range.begin_pos
130
132
 
131
- count = blank_lines_count_between(prev_def, node)
132
-
133
133
  if count > maximum_empty_lines
134
134
  autocorrect_remove_lines(corrector, newline_pos, count)
135
135
  else
@@ -157,14 +157,22 @@ module RuboCop
157
157
  cop_config['EmptyLineBetweenModuleDefs'] && node.module_type?
158
158
  end
159
159
 
160
- def message(node)
161
- type = case node.type
162
- when :def, :defs
163
- :method
164
- else
165
- node.type
166
- end
167
- format(MSG, type: type)
160
+ def message(node, count: nil)
161
+ type = node_type(node)
162
+
163
+ format(MSG,
164
+ type: type,
165
+ expected: expected_lines,
166
+ actual: count)
167
+ end
168
+
169
+ def expected_lines
170
+ if allowance_range?
171
+ "#{minimum_empty_lines..maximum_empty_lines} empty lines"
172
+ else
173
+ lines = maximum_empty_lines == 1 ? 'line' : 'lines'
174
+ "#{maximum_empty_lines} empty #{lines}"
175
+ end
168
176
  end
169
177
 
170
178
  def multiple_blank_lines_groups?(first_def_node, second_def_node)
@@ -176,8 +184,7 @@ module RuboCop
176
184
  blank_start > non_blank_end
177
185
  end
178
186
 
179
- def blank_lines_between?(first_def_node, second_def_node)
180
- count = blank_lines_count_between(first_def_node, second_def_node)
187
+ def line_count_allowed?(count)
181
188
  (minimum_empty_lines..maximum_empty_lines).cover?(count)
182
189
  end
183
190
 
@@ -210,7 +217,7 @@ module RuboCop
210
217
  end
211
218
 
212
219
  def end_loc(node)
213
- if node.def_type? && node.endless?
220
+ if (node.def_type? || node.defs_type?) && node.endless?
214
221
  node.loc.expression.end
215
222
  else
216
223
  node.loc.end
@@ -230,6 +237,19 @@ module RuboCop
230
237
 
231
238
  corrector.insert_after(where_to_insert, "\n" * difference)
232
239
  end
240
+
241
+ def node_type(node)
242
+ case node.type
243
+ when :def, :defs
244
+ :method
245
+ else
246
+ node.type
247
+ end
248
+ end
249
+
250
+ def allowance_range?
251
+ minimum_empty_lines != maximum_empty_lines
252
+ end
233
253
  end
234
254
  end
235
255
  end
@@ -4,11 +4,14 @@ module RuboCop
4
4
  module Cop
5
5
  module Layout
6
6
  # This cop checks the indentation of the first argument in a method call.
7
- # Arguments after the first one are checked by Layout/ArgumentAlignment,
7
+ # Arguments after the first one are checked by `Layout/ArgumentAlignment`,
8
8
  # not by this cop.
9
9
  #
10
10
  # For indenting the first parameter of method _definitions_, check out
11
- # Layout/FirstParameterIndentation.
11
+ # `Layout/FirstParameterIndentation`.
12
+ #
13
+ # This cop will respect `Layout/ArgumentAlignment` and will not work when
14
+ # `EnforcedStyle: with_fixed_indentation` is specified for `Layout/ArgumentAlignment`.
12
15
  #
13
16
  # @example
14
17
  #
@@ -149,6 +152,7 @@ module RuboCop
149
152
  MSG = 'Indent the first argument one step more than %<base>s.'
150
153
 
151
154
  def on_send(node)
155
+ return if style != :consistent && enforce_first_argument_with_fixed_indentation?
152
156
  return if !node.arguments? || node.operator_method?
153
157
 
154
158
  indent = base_indentation(node) + configured_indentation_width
@@ -250,6 +254,16 @@ module RuboCop
250
254
  def on_new_investigation
251
255
  @comment_lines = nil
252
256
  end
257
+
258
+ def enforce_first_argument_with_fixed_indentation?
259
+ return false unless argument_alignment_config['Enabled']
260
+
261
+ argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
262
+ end
263
+
264
+ def argument_alignment_config
265
+ config.for_cop('Layout/ArgumentAlignment')
266
+ end
253
267
  end
254
268
  end
255
269
  end
@@ -60,12 +60,13 @@ module RuboCop
60
60
  # }
61
61
  class LineLength < Base
62
62
  include CheckLineBreakable
63
- include ConfigurableMax
64
63
  include IgnoredPattern
65
64
  include RangeHelp
66
65
  include LineLengthHelp
67
66
  extend AutoCorrector
68
67
 
68
+ exclude_limit 'Max'
69
+
69
70
  MSG = 'Line is too long. [%<length>d/%<max>d]'
70
71
 
71
72
  def on_block(node)
@@ -31,6 +31,32 @@ module RuboCop
31
31
  # foo = if expression
32
32
  # 'bar'
33
33
  # end
34
+ #
35
+ # @example SupportedTypes: ['block', 'case', 'class', 'if', 'kwbegin', 'module'] (default)
36
+ # # good
37
+ # foo =
38
+ # if expression
39
+ # 'bar'
40
+ # end
41
+ #
42
+ # # good
43
+ # foo =
44
+ # [1].map do |i|
45
+ # i + 1
46
+ # end
47
+ #
48
+ # @example SupportedTypes: ['block']
49
+ # # good
50
+ # foo = if expression
51
+ # 'bar'
52
+ # end
53
+ #
54
+ # # good
55
+ # foo =
56
+ # [1].map do |i|
57
+ # 'bar' * i
58
+ # end
59
+ #
34
60
  class MultilineAssignmentLayout < Base
35
61
  include CheckAssignment
36
62
  include ConfigurableEnforcedStyle
@@ -16,14 +16,14 @@ module RuboCop
16
16
  # if a +
17
17
  # b
18
18
  # something &&
19
- # something_else
19
+ # something_else
20
20
  # end
21
21
  #
22
22
  # # good
23
23
  # if a +
24
24
  # b
25
25
  # something &&
26
- # something_else
26
+ # something_else
27
27
  # end
28
28
  #
29
29
  # @example EnforcedStyle: indented
@@ -6,10 +6,6 @@ module RuboCop
6
6
  # Checks for space between the name of a receiver and a left
7
7
  # brackets.
8
8
  #
9
- # This cop is marked as unsafe because it can occur false positives
10
- # for `do_something [this_is_an_array_literal_argument]` that take
11
- # an array without parentheses as an argument.
12
- #
13
9
  # @example
14
10
  #
15
11
  # # bad
@@ -25,28 +21,35 @@ module RuboCop
25
21
  MSG = 'Remove the space before the opening brackets.'
26
22
 
27
23
  def on_send(node)
28
- return if node.parenthesized? || node.parent&.send_type?
29
24
  return unless (first_argument = node.first_argument)
30
25
 
31
26
  begin_pos = first_argument.source_range.begin_pos
32
-
33
- return unless (range = offense_range(node, first_argument, begin_pos))
27
+ return unless (range = offense_range(node, begin_pos))
34
28
 
35
29
  register_offense(range)
36
30
  end
37
31
 
38
32
  private
39
33
 
40
- def offense_range(node, first_argument, begin_pos)
41
- if space_before_brackets?(node, first_argument)
42
- range_between(node.loc.selector.end_pos, begin_pos)
34
+ def offense_range(node, begin_pos)
35
+ if reference_variable_with_brackets?(node)
36
+ receiver_end_pos = node.receiver.source_range.end_pos
37
+ selector_begin_pos = node.loc.selector.begin_pos
38
+ return if receiver_end_pos >= selector_begin_pos
39
+
40
+ range_between(receiver_end_pos, selector_begin_pos)
43
41
  elsif node.method?(:[]=)
44
- end_pos = node.receiver.source_range.end_pos
42
+ offense_range_for_assignment(node, begin_pos)
43
+ end
44
+ end
45
45
 
46
- return if begin_pos - end_pos == 1
46
+ def offense_range_for_assignment(node, begin_pos)
47
+ end_pos = node.receiver.source_range.end_pos
47
48
 
48
- range_between(end_pos, begin_pos - 1)
49
- end
49
+ return if begin_pos - end_pos == 1 ||
50
+ (range = range_between(end_pos, begin_pos - 1)).source.start_with?('[')
51
+
52
+ range
50
53
  end
51
54
 
52
55
  def register_offense(range)
@@ -55,8 +58,8 @@ module RuboCop
55
58
  end
56
59
  end
57
60
 
58
- def space_before_brackets?(node, first_argument)
59
- node.receiver.nil? && first_argument.array_type? && node.arguments.size == 1
61
+ def reference_variable_with_brackets?(node)
62
+ node.receiver&.variable? && node.method?(:[]) && node.arguments.size == 1
60
63
  end
61
64
  end
62
65
  end
@@ -3,8 +3,21 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop checks for calls to debugger or pry.
7
- # The cop can be configured to define which methods and receivers must be fixed.
6
+ # This cop checks for debug calls (such as `debugger` or `binding.pry`) that should
7
+ # not be kept for production code.
8
+ #
9
+ # The cop can be configured using `DebuggerMethods`. By default, a number of gems
10
+ # debug entrypoints are configured (`Kernel`, `Byebug`, `Capybara`, `Pry`, `Rails`,
11
+ # and `WebConsole`). Additional methods can be added.
12
+ #
13
+ # Specific default groups can be disabled if necessary:
14
+ #
15
+ # [source,yaml]
16
+ # ----
17
+ # Lint/Debugger:
18
+ # WebConsole: ~
19
+ # ---
20
+ #
8
21
  #
9
22
  # @example
10
23
  #
@@ -33,14 +46,32 @@ module RuboCop
33
46
  # def some_method
34
47
  # do_something
35
48
  # end
49
+ #
50
+ # @example DebuggerMethods: [my_debugger]
51
+ #
52
+ # # bad (ok during development)
53
+ #
54
+ # def some_method
55
+ # my_debugger
56
+ # end
36
57
  class Debugger < Base
37
58
  MSG = 'Remove debugger entry point `%<source>s`.'
38
59
 
39
60
  RESTRICT_ON_SEND = [].freeze
40
61
 
62
+ def_node_matcher :kernel?, <<~PATTERN
63
+ (const {nil? cbase} :Kernel)
64
+ PATTERN
65
+
66
+ def_node_matcher :valid_receiver?, <<~PATTERN
67
+ {
68
+ (const {nil? cbase} %1)
69
+ (send {nil? #kernel?} %1)
70
+ }
71
+ PATTERN
72
+
41
73
  def on_send(node)
42
- return unless debugger_method?(node.method_name)
43
- return if !node.receiver.nil? && !debugger_receiver?(node)
74
+ return unless debugger_method?(node)
44
75
 
45
76
  add_offense(node)
46
77
  end
@@ -51,19 +82,32 @@ module RuboCop
51
82
  format(MSG, source: node.source)
52
83
  end
53
84
 
54
- def debugger_method?(name)
55
- cop_config.fetch('DebuggerMethods', []).include?(name.to_s)
85
+ def debugger_methods
86
+ @debugger_methods ||= begin
87
+ config = cop_config.fetch('DebuggerMethods', [])
88
+ values = config.is_a?(Array) ? config : config.values.flatten
89
+ values.map do |v|
90
+ next unless v
91
+
92
+ *receiver, method_name = v.split('.')
93
+ {
94
+ receiver: receiver.empty? ? nil : receiver.join.to_sym,
95
+ method_name: method_name.to_sym
96
+ }
97
+ end.compact
98
+ end
56
99
  end
57
100
 
58
- def debugger_receiver?(node)
59
- receiver = case node.receiver
60
- when RuboCop::AST::SendNode
61
- node.receiver.method_name
62
- when RuboCop::AST::ConstNode
63
- node.receiver.const_name
64
- end
101
+ def debugger_method?(send_node)
102
+ debugger_methods.any? do |method|
103
+ next unless method[:method_name] == send_node.method_name
65
104
 
66
- cop_config.fetch('DebuggerReceivers', []).include?(receiver.to_s)
105
+ if method[:receiver].nil?
106
+ send_node.receiver.nil?
107
+ else
108
+ valid_receiver?(send_node.receiver, method[:receiver])
109
+ end
110
+ end
67
111
  end
68
112
  end
69
113
  end