rubocop 0.93.0 → 1.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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -16
  3. data/config/default.yml +207 -77
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop.rb +16 -2
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  7. data/lib/rubocop/cli/command/version.rb +1 -1
  8. data/lib/rubocop/comment_config.rb +1 -1
  9. data/lib/rubocop/config.rb +4 -0
  10. data/lib/rubocop/config_loader.rb +26 -8
  11. data/lib/rubocop/config_loader_resolver.rb +7 -5
  12. data/lib/rubocop/config_validator.rb +7 -6
  13. data/lib/rubocop/cop/badge.rb +9 -24
  14. data/lib/rubocop/cop/base.rb +16 -1
  15. data/lib/rubocop/cop/bundler/duplicated_gem.rb +26 -6
  16. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  17. data/lib/rubocop/cop/commissioner.rb +37 -23
  18. data/lib/rubocop/cop/corrector.rb +3 -1
  19. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  20. data/lib/rubocop/cop/force.rb +1 -1
  21. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
  22. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
  23. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  24. data/lib/rubocop/cop/generator.rb +1 -1
  25. data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
  26. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  27. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  28. data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
  29. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  30. data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
  31. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
  32. data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
  33. data/lib/rubocop/cop/layout/line_length.rb +8 -1
  34. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
  35. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  36. data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
  37. data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
  38. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -3
  39. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +23 -2
  40. data/lib/rubocop/cop/lint/debugger.rb +17 -28
  41. data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
  42. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
  43. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
  44. data/lib/rubocop/cop/lint/else_layout.rb +29 -3
  45. data/lib/rubocop/cop/lint/empty_block.rb +82 -0
  46. data/lib/rubocop/cop/lint/empty_class.rb +93 -0
  47. data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
  48. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +38 -6
  49. data/lib/rubocop/cop/lint/loop.rb +4 -4
  50. data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
  52. data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
  53. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
  54. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
  55. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +44 -11
  56. data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
  57. data/lib/rubocop/cop/lint/to_enum_arguments.rb +95 -0
  58. data/lib/rubocop/cop/lint/to_json.rb +1 -1
  59. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +185 -0
  60. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  61. data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
  62. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
  63. data/lib/rubocop/cop/metrics/class_length.rb +9 -3
  64. data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
  65. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  66. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
  67. data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
  68. data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
  69. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
  70. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
  71. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
  72. data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
  73. data/lib/rubocop/cop/naming/variable_number.rb +98 -8
  74. data/lib/rubocop/cop/offense.rb +3 -3
  75. data/lib/rubocop/cop/security/open.rb +12 -10
  76. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  77. data/lib/rubocop/cop/style/and_or.rb +1 -3
  78. data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
  79. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
  80. data/lib/rubocop/cop/style/case_like_if.rb +0 -4
  81. data/lib/rubocop/cop/style/class_equality_comparison.rb +19 -4
  82. data/lib/rubocop/cop/style/collection_compact.rb +91 -0
  83. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +162 -0
  84. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  85. data/lib/rubocop/cop/style/format_string_token.rb +47 -2
  86. data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
  87. data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
  88. data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
  89. data/lib/rubocop/cop/style/if_unless_modifier.rb +7 -3
  90. data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
  91. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
  93. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
  94. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
  95. data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
  96. data/lib/rubocop/cop/style/multiple_comparison.rb +55 -7
  97. data/lib/rubocop/cop/style/negated_if_else_condition.rb +104 -0
  98. data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
  99. data/lib/rubocop/cop/style/raise_args.rb +21 -6
  100. data/lib/rubocop/cop/style/redundant_begin.rb +14 -4
  101. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  102. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -1
  103. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  104. data/lib/rubocop/cop/style/redundant_self.rb +3 -0
  105. data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
  106. data/lib/rubocop/cop/style/semicolon.rb +3 -0
  107. data/lib/rubocop/cop/style/static_class.rb +97 -0
  108. data/lib/rubocop/cop/style/string_concatenation.rb +13 -1
  109. data/lib/rubocop/cop/style/swap_values.rb +108 -0
  110. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  111. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
  112. data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
  113. data/lib/rubocop/cop/team.rb +6 -1
  114. data/lib/rubocop/cop/util.rb +5 -1
  115. data/lib/rubocop/ext/regexp_node.rb +17 -9
  116. data/lib/rubocop/ext/regexp_parser.rb +84 -0
  117. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  118. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
  119. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  120. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  121. data/lib/rubocop/magic_comment.rb +2 -2
  122. data/lib/rubocop/options.rb +6 -1
  123. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  124. data/lib/rubocop/target_ruby.rb +57 -1
  125. data/lib/rubocop/version.rb +56 -6
  126. metadata +21 -5
@@ -255,7 +255,7 @@ module RuboCop
255
255
  PATTERN
256
256
  end
257
257
 
258
- send(matcher_name, child)
258
+ public_send(matcher_name, child)
259
259
  end
260
260
  end
261
261
 
@@ -279,7 +279,7 @@ module RuboCop
279
279
  PATTERN
280
280
  end
281
281
 
282
- send(matcher_name, child)
282
+ public_send(matcher_name, child)
283
283
  end
284
284
  end
285
285
  end
@@ -54,11 +54,9 @@ module RuboCop
54
54
  end
55
55
 
56
56
  def delegating?(node, def_node)
57
- if node.nil?
58
- false
59
- elsif node.zsuper_type?
57
+ if node&.zsuper_type?
60
58
  true
61
- elsif node.super_type?
59
+ elsif node&.super_type?
62
60
  node.arguments.map(&:source) == def_node.arguments.map(&:source)
63
61
  else
64
62
  false
@@ -5,6 +5,7 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for setter call to local variable as the final
7
7
  # expression of a function definition.
8
+ # Its auto-correction is marked as unsafe because return value will be changed.
8
9
  #
9
10
  # NOTE: There are edge cases in which the local variable references a
10
11
  # value that is also accessible outside the local scope. This is not
@@ -29,6 +30,8 @@ module RuboCop
29
30
  # x
30
31
  # end
31
32
  class UselessSetterCall < Base
33
+ extend AutoCorrector
34
+
32
35
  MSG = 'Useless setter call to local variable `%<variable>s`.'
33
36
  ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn].freeze
34
37
 
@@ -45,7 +48,9 @@ module RuboCop
45
48
 
46
49
  loc_name = receiver.loc.name
47
50
 
48
- add_offense(loc_name, message: format(MSG, variable: loc_name.source))
51
+ add_offense(loc_name, message: format(MSG, variable: loc_name.source)) do |corrector|
52
+ corrector.insert_after(last_expr, "\n#{indent(last_expr)}#{loc_name.source}")
53
+ end
49
54
  end
50
55
  alias on_defs on_def
51
56
 
@@ -39,13 +39,19 @@ module RuboCop
39
39
  end
40
40
 
41
41
  def on_casgn(node)
42
- if node.parent&.assignment?
43
- block_node = node.parent.children[1]
42
+ parent = node.parent
43
+
44
+ if parent&.assignment?
45
+ block_node = parent.children[1]
46
+ elsif parent&.parent&.masgn_type?
47
+ block_node = parent.parent.children[1]
44
48
  else
45
49
  _scope, _name, block_node = *node
46
50
  end
47
51
 
48
- check_code_length(block_node) if block_node.class_definition?
52
+ return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
53
+
54
+ check_code_length(block_node)
49
55
  end
50
56
 
51
57
  private
@@ -12,6 +12,9 @@ module RuboCop
12
12
  MSG = 'Avoid parameter lists longer than %<max>d parameters. ' \
13
13
  '[%<count>d/%<max>d]'
14
14
 
15
+ NAMED_KEYWORD_TYPES = %i[kwoptarg kwarg].freeze
16
+ private_constant :NAMED_KEYWORD_TYPES
17
+
15
18
  def on_args(node)
16
19
  count = args_count(node)
17
20
  return unless count > max_params
@@ -33,7 +36,7 @@ module RuboCop
33
36
  if count_keyword_args?
34
37
  node.children.size
35
38
  else
36
- node.children.count { |a| !%i[kwoptarg kwarg].include?(a.type) }
39
+ node.children.count { |a| !NAMED_KEYWORD_TYPES.include?(a.type) }
37
40
  end
38
41
  end
39
42
 
@@ -103,7 +103,7 @@ module RuboCop
103
103
  # hashes wrapped in a set of curly braces like {foo: 1}.
104
104
  # That is, not a kwargs hash. For method calls, this ensures
105
105
  # the method call is made with parens.
106
- starts_with_bracket = node.loc.begin
106
+ starts_with_bracket = !node.hash_type? || node.loc.begin
107
107
 
108
108
  # If the call has a second argument, we can insert a line
109
109
  # break before the second argument and the rest of the
@@ -8,9 +8,9 @@ module RuboCop
8
8
  include ConfigurableFormatting
9
9
 
10
10
  FORMATS = {
11
- snake_case: /(?:[[[:lower:]]_]|_\d+)$/,
12
- normalcase: /(?:_\D*|[[[:upper:]][[:lower:]]]\d*)$/,
13
- non_integer: /[[[:upper:]][[:lower:]]_]$/
11
+ snake_case: /(?:\D|_\d+)$/,
12
+ normalcase: /(?:\D|[^_\d]\d+)$/,
13
+ non_integer: /\D$/
14
14
  }.freeze
15
15
  end
16
16
  end
@@ -57,7 +57,7 @@ module RuboCop
57
57
  def indentation_difference(line)
58
58
  return 0 unless tab_indentation_width
59
59
 
60
- line.match(/^\t*/)[0].size * (tab_indentation_width - 1)
60
+ (line.index(/[^\t]/) || 0) * (tab_indentation_width - 1)
61
61
  end
62
62
 
63
63
  def tab_indentation_width
@@ -19,7 +19,8 @@ module RuboCop
19
19
  def non_eligible_node?(node)
20
20
  node.modifier_form? ||
21
21
  node.nonempty_line_count > 3 ||
22
- processed_source.line_with_comment?(node.loc.last_line)
22
+ processed_source.line_with_comment?(node.loc.last_line) ||
23
+ (first_line_comment(node) && code_after(node))
23
24
  end
24
25
 
25
26
  def non_eligible_body?(body)
@@ -41,11 +42,9 @@ module RuboCop
41
42
 
42
43
  def length_in_modifier_form(node)
43
44
  keyword_element = node.loc.keyword
44
- end_element = node.loc.end
45
45
  code_before = keyword_element.source_line[0...keyword_element.column]
46
- code_after = end_element.source_line[end_element.last_column..-1]
47
46
  expression = to_modifier_form(node)
48
- line_length("#{code_before}#{expression}#{code_after}")
47
+ line_length("#{code_before}#{expression}#{code_after(node)}")
49
48
  end
50
49
 
51
50
  def to_modifier_form(node)
@@ -64,6 +63,12 @@ module RuboCop
64
63
  comment_source unless comment_disables_cop?(comment_source)
65
64
  end
66
65
 
66
+ def code_after(node)
67
+ end_element = node.loc.end
68
+ code = end_element.source_line[end_element.last_column..-1]
69
+ code unless code.empty?
70
+ end
71
+
67
72
  def parenthesize?(node)
68
73
  # Parenthesize corrected expression if changing to modifier-if form
69
74
  # would change the meaning of the parent expression
@@ -14,11 +14,13 @@ module RuboCop
14
14
  # # good
15
15
  # def +(other); end
16
16
  class BinaryOperatorParameterName < Base
17
+ extend AutoCorrector
18
+
17
19
  MSG = 'When defining the `%<opr>s` operator, ' \
18
20
  'name its argument `other`.'
19
21
 
20
22
  OP_LIKE_METHODS = %i[eql? equal?].freeze
21
- EXCLUDED = %i[+@ -@ [] []= << === `].freeze
23
+ EXCLUDED = %i[+@ -@ [] []= << === ` =~].freeze
22
24
 
23
25
  def_node_matcher :op_method_candidate?, <<~PATTERN
24
26
  (def [#op_method? $_] (args $(arg [!:other !:_other])) _)
@@ -26,7 +28,15 @@ module RuboCop
26
28
 
27
29
  def on_def(node)
28
30
  op_method_candidate?(node) do |name, arg|
29
- add_offense(arg, message: format(MSG, opr: name))
31
+ add_offense(arg, message: format(MSG, opr: name)) do |corrector|
32
+ corrector.replace(arg, 'other')
33
+ node.each_descendant(:lvar, :lvasgn) do |lvar|
34
+ lvar_location = lvar.loc.name
35
+ next unless lvar_location.source == arg.source
36
+
37
+ corrector.replace(lvar_location, 'other')
38
+ end
39
+ end
30
40
  end
31
41
  end
32
42
 
@@ -30,13 +30,19 @@ module RuboCop
30
30
  class HeredocDelimiterCase < Base
31
31
  include Heredoc
32
32
  include ConfigurableEnforcedStyle
33
+ extend AutoCorrector
33
34
 
34
35
  MSG = 'Use %<style>s heredoc delimiters.'
35
36
 
36
37
  def on_heredoc(node)
37
38
  return if correct_case_delimiters?(node)
38
39
 
39
- add_offense(node.loc.heredoc_end)
40
+ add_offense(node.loc.heredoc_end) do |corrector|
41
+ expr = node.loc.expression
42
+
43
+ corrector.replace(expr, correct_delimiters(expr.source))
44
+ corrector.replace(node.loc.heredoc_end, correct_delimiters(delimiter_string(expr)))
45
+ end
40
46
  end
41
47
 
42
48
  private
@@ -46,14 +52,14 @@ module RuboCop
46
52
  end
47
53
 
48
54
  def correct_case_delimiters?(node)
49
- delimiter_string(node) == correct_delimiters(node)
55
+ delimiter_string(node) == correct_delimiters(delimiter_string(node))
50
56
  end
51
57
 
52
- def correct_delimiters(node)
58
+ def correct_delimiters(source)
53
59
  if style == :uppercase
54
- delimiter_string(node).upcase
60
+ source.upcase
55
61
  else
56
- delimiter_string(node).downcase
62
+ source.downcase
57
63
  end
58
64
  end
59
65
  end
@@ -20,6 +20,11 @@ module RuboCop
20
20
  # @something ||= calculate_expensive_thing
21
21
  # end
22
22
  #
23
+ # def foo
24
+ # return @something if defined?(@something)
25
+ # @something = calculate_expensive_thing
26
+ # end
27
+ #
23
28
  # # good
24
29
  # def _foo
25
30
  # @foo ||= calculate_expensive_thing
@@ -54,6 +59,11 @@ module RuboCop
54
59
  # @foo ||= calculate_expensive_thing
55
60
  # end
56
61
  #
62
+ # def foo
63
+ # return @foo if defined?(@foo)
64
+ # @foo = calculate_expensive_thing
65
+ # end
66
+ #
57
67
  # # good
58
68
  # def foo
59
69
  # @_foo ||= calculate_expensive_thing
@@ -64,6 +74,11 @@ module RuboCop
64
74
  # @_foo ||= calculate_expensive_thing
65
75
  # end
66
76
  #
77
+ # def foo
78
+ # return @_foo if defined?(@_foo)
79
+ # @_foo = calculate_expensive_thing
80
+ # end
81
+ #
67
82
  # @example EnforcedStyleForLeadingUnderscores :optional
68
83
  # # bad
69
84
  # def foo
@@ -84,6 +99,12 @@ module RuboCop
84
99
  # def _foo
85
100
  # @_foo ||= calculate_expensive_thing
86
101
  # end
102
+ #
103
+ # # good
104
+ # def foo
105
+ # return @_foo if defined?(@_foo)
106
+ # @_foo = calculate_expensive_thing
107
+ # end
87
108
  class MemoizedInstanceVariableName < Base
88
109
  include ConfigurableEnforcedStyle
89
110
 
@@ -92,32 +113,60 @@ module RuboCop
92
113
  UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
93
114
  'with `_`. Use `@%<suggested_var>s` instead.'
94
115
 
95
- def self.node_pattern
96
- memo_assign = '(or_asgn $(ivasgn _) _)'
97
- memoized_at_end_of_method = "(begin ... #{memo_assign})"
98
- instance_method =
99
- "(def $_ _ {#{memo_assign} #{memoized_at_end_of_method}})"
100
- class_method =
101
- "(defs self $_ _ {#{memo_assign} #{memoized_at_end_of_method}})"
102
- "{#{instance_method} #{class_method}}"
103
- end
116
+ # rubocop:disable Metrics/AbcSize
117
+ def on_or_asgn(node)
118
+ lhs, _value = *node
119
+ return unless lhs.ivasgn_type?
120
+ return unless (method_node = node.each_ancestor(:def, :defs).first)
104
121
 
105
- private_class_method :node_pattern
106
- def_node_matcher :memoized?, node_pattern
122
+ body = method_node.body
123
+ return unless body == node || body.children.last == node
107
124
 
108
- def on_def(node)
109
- (method_name, ivar_assign) = memoized?(node)
110
- return if matches?(method_name, ivar_assign)
125
+ method_name = method_node.method_name
126
+ return if matches?(method_name, lhs)
111
127
 
112
128
  msg = format(
113
- message(ivar_assign.children.first.to_s),
114
- var: ivar_assign.children.first.to_s,
129
+ message(lhs.children.first.to_s),
130
+ var: lhs.children.first.to_s,
115
131
  suggested_var: suggested_var(method_name),
116
132
  method: method_name
117
133
  )
118
- add_offense(ivar_assign.source_range, message: msg)
134
+ add_offense(lhs, message: msg)
135
+ end
136
+ # rubocop:enable Metrics/AbcSize
137
+
138
+ def_node_matcher :defined_memoized?, <<~PATTERN
139
+ (begin
140
+ (if (defined $(ivar %1)) (return $(ivar %1)) nil?)
141
+ ...
142
+ $(ivasgn %1 _))
143
+ PATTERN
144
+
145
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
146
+ def on_defined?(node)
147
+ arg = node.arguments.first
148
+ return unless arg.ivar_type?
149
+
150
+ method_node = node.each_ancestor(:def, :defs).first
151
+ return unless method_node
152
+
153
+ var_name = arg.children.first
154
+ method_name = method_node.method_name
155
+ defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
156
+ return if matches?(method_name, ivar_assign)
157
+
158
+ msg = format(
159
+ message(var_name.to_s),
160
+ var: var_name.to_s,
161
+ suggested_var: suggested_var(method_name),
162
+ method: method_name
163
+ )
164
+ add_offense(defined_ivar, message: msg)
165
+ add_offense(return_ivar, message: msg)
166
+ add_offense(ivar_assign.loc.name, message: msg)
167
+ end
119
168
  end
120
- alias on_defs on_def
169
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
121
170
 
122
171
  private
123
172
 
@@ -67,7 +67,8 @@ module RuboCop
67
67
  private
68
68
 
69
69
  def allowed_method_name?(method_name, prefix)
70
- !method_name.match?(/^#{prefix}[^0-9]/) ||
70
+ !(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
71
+ method_name.match?(/^#{prefix}[^0-9]/)) ||
71
72
  method_name == expected_name(method_name, prefix) ||
72
73
  method_name.end_with?('=') ||
73
74
  allowed_method?(method_name)
@@ -7,42 +7,102 @@ module RuboCop
7
7
  # configured style, snake_case, normalcase, or non_integer,
8
8
  # for their numbering.
9
9
  #
10
+ # Additionally, `CheckMethodNames` and `CheckSymbols` configuration options
11
+ # can be used to specify whether method names and symbols should be checked.
12
+ # Both are enabled by default.
13
+ #
10
14
  # @example EnforcedStyle: snake_case
11
15
  # # bad
12
- #
16
+ # :some_sym1
13
17
  # variable1 = 1
14
18
  #
15
- # # good
19
+ # def some_method1; end
16
20
  #
21
+ # def some_method_1(arg1); end
22
+ #
23
+ # # good
24
+ # :some_sym_1
17
25
  # variable_1 = 1
18
26
  #
27
+ # def some_method_1; end
28
+ #
29
+ # def some_method_1(arg_1); end
30
+ #
19
31
  # @example EnforcedStyle: normalcase (default)
20
32
  # # bad
21
- #
33
+ # :some_sym_1
22
34
  # variable_1 = 1
23
35
  #
24
- # # good
36
+ # def some_method_1; end
25
37
  #
38
+ # def some_method1(arg_1); end
39
+ #
40
+ # # good
41
+ # :some_sym1
26
42
  # variable1 = 1
27
43
  #
44
+ # def some_method1; end
45
+ #
46
+ # def some_method1(arg1); end
47
+ #
28
48
  # @example EnforcedStyle: non_integer
29
49
  # # bad
50
+ # :some_sym1
51
+ # :some_sym_1
30
52
  #
31
53
  # variable1 = 1
32
- #
33
54
  # variable_1 = 1
34
55
  #
56
+ # def some_method1; end
57
+ #
58
+ # def some_method_1; end
59
+ #
60
+ # def some_methodone(arg1); end
61
+ # def some_methodone(arg_1); end
62
+ #
35
63
  # # good
64
+ # :some_symone
65
+ # :some_sym_one
36
66
  #
37
67
  # variableone = 1
38
- #
39
68
  # variable_one = 1
69
+ #
70
+ # def some_methodone; end
71
+ #
72
+ # def some_method_one; end
73
+ #
74
+ # def some_methodone(argone); end
75
+ # def some_methodone(arg_one); end
76
+ #
77
+ # # In the following examples, we assume `EnforcedStyle: normalcase` (default).
78
+ #
79
+ # @example CheckMethodNames: true (default)
80
+ # # bad
81
+ # def some_method_1; end
82
+ #
83
+ # @example CheckMethodNames: false
84
+ # # good
85
+ # def some_method_1; end
86
+ #
87
+ # @example CheckSymbols: true (default)
88
+ # # bad
89
+ # :some_sym_1
90
+ #
91
+ # @example CheckSymbols: false
92
+ # # good
93
+ # :some_sym_1
94
+ #
95
+ # @example AllowedIdentifier: [capture3]
96
+ # # good
97
+ # expect(Open3).to receive(:capture3)
98
+ #
40
99
  class VariableNumber < Base
41
100
  include ConfigurableNumbering
42
101
 
43
- MSG = 'Use %<style>s for variable numbers.'
102
+ MSG = 'Use %<style>s for %<identifier_type>s numbers.'
44
103
 
45
104
  def on_arg(node)
105
+ @node = node
46
106
  name, = *node
47
107
  check_name(node, name, node.loc.name)
48
108
  end
@@ -50,10 +110,40 @@ module RuboCop
50
110
  alias on_ivasgn on_arg
51
111
  alias on_cvasgn on_arg
52
112
 
113
+ def on_def(node)
114
+ @node = node
115
+ return if allowed_identifier?(node.method_name)
116
+
117
+ check_name(node, node.method_name, node.loc.name) if cop_config['CheckMethodNames']
118
+ end
119
+ alias on_defs on_def
120
+
121
+ def on_sym(node)
122
+ @node = node
123
+ return if allowed_identifier?(node.value)
124
+
125
+ check_name(node, node.value, node) if cop_config['CheckSymbols']
126
+ end
127
+
53
128
  private
54
129
 
55
130
  def message(style)
56
- format(MSG, style: style)
131
+ identifier_type =
132
+ case @node.type
133
+ when :def, :defs then 'method name'
134
+ when :sym then 'symbol'
135
+ else 'variable'
136
+ end
137
+
138
+ format(MSG, style: style, identifier_type: identifier_type)
139
+ end
140
+
141
+ def allowed_identifier?(name)
142
+ allowed_identifiers.include?(name.to_s)
143
+ end
144
+
145
+ def allowed_identifiers
146
+ cop_config.fetch('AllowedIdentifiers', [])
57
147
  end
58
148
  end
59
149
  end