rubocop 1.63.0 → 1.64.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/config/default.yml +18 -3
  4. data/lib/rubocop/cached_data.rb +11 -3
  5. data/lib/rubocop/cli/command/show_docs_url.rb +2 -2
  6. data/lib/rubocop/cli.rb +4 -0
  7. data/lib/rubocop/config.rb +2 -3
  8. data/lib/rubocop/cop/base.rb +9 -14
  9. data/lib/rubocop/cop/bundler/gem_version.rb +3 -5
  10. data/lib/rubocop/cop/documentation.rb +16 -6
  11. data/lib/rubocop/cop/force.rb +12 -0
  12. data/lib/rubocop/cop/gemspec/dependency_version.rb +3 -5
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  14. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  15. data/lib/rubocop/cop/layout/empty_comment.rb +3 -1
  16. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -0
  17. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +3 -4
  18. data/lib/rubocop/cop/lint/assignment_in_condition.rb +3 -1
  19. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  20. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  21. data/lib/rubocop/cop/lint/erb_new_arguments.rb +21 -14
  22. data/lib/rubocop/cop/lint/mixed_case_range.rb +9 -4
  23. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  24. data/lib/rubocop/cop/lint/unreachable_code.rb +4 -2
  25. data/lib/rubocop/cop/lint/unreachable_loop.rb +8 -2
  26. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -5
  27. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +9 -2
  28. data/lib/rubocop/cop/security/compound_hash.rb +2 -2
  29. data/lib/rubocop/cop/style/access_modifier_declarations.rb +50 -0
  30. data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -2
  31. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  32. data/lib/rubocop/cop/style/copyright.rb +15 -10
  33. data/lib/rubocop/cop/style/documentation.rb +24 -24
  34. data/lib/rubocop/cop/style/documentation_method.rb +20 -0
  35. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  36. data/lib/rubocop/cop/style/hash_syntax.rb +18 -0
  37. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -3
  38. data/lib/rubocop/cop/style/map_into_array.rb +3 -3
  39. data/lib/rubocop/cop/style/numeric_predicate.rb +10 -2
  40. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  41. data/lib/rubocop/cop/style/redundant_line_continuation.rb +4 -1
  42. data/lib/rubocop/cop/style/require_order.rb +1 -1
  43. data/lib/rubocop/cop/style/send.rb +4 -4
  44. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +90 -0
  45. data/lib/rubocop/cop/style/special_global_vars.rb +1 -2
  46. data/lib/rubocop/cop/style/super_arguments.rb +156 -0
  47. data/lib/rubocop/cop/style/symbol_proc.rb +32 -5
  48. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  49. data/lib/rubocop/cop/team.rb +2 -0
  50. data/lib/rubocop/formatter/disabled_config_formatter.rb +13 -9
  51. data/lib/rubocop/formatter/formatter_set.rb +7 -1
  52. data/lib/rubocop/lockfile.rb +25 -6
  53. data/lib/rubocop/lsp/routes.rb +10 -13
  54. data/lib/rubocop/lsp/server.rb +2 -0
  55. data/lib/rubocop/lsp.rb +9 -2
  56. data/lib/rubocop/options.rb +3 -3
  57. data/lib/rubocop/rake_task.rb +1 -1
  58. data/lib/rubocop/runner.rb +5 -4
  59. data/lib/rubocop/version.rb +4 -4
  60. data/lib/rubocop.rb +2 -0
  61. metadata +10 -8
@@ -8,6 +8,17 @@ module RuboCop
8
8
  # EnforcedStyle config covers only method definitions.
9
9
  # Applications of visibility methods to symbols can be controlled
10
10
  # using AllowModifiersOnSymbols config.
11
+ # Also, the visibility of `attr*` methods can be controlled using
12
+ # AllowModifiersOnAttrs config.
13
+ #
14
+ # In Ruby 3.0, `attr*` methods now return an array of defined method names
15
+ # as symbols. So we can write the modifier and `attr*` in inline style.
16
+ # AllowModifiersOnAttrs config allows `attr*` methods to be written in
17
+ # inline style without modifying applications that have been maintained
18
+ # for a long time in group style. Furthermore, developers who are not very
19
+ # familiar with Ruby may know that the modifier applies to `def`, but they
20
+ # may not know that it also applies to `attr*` methods. It would be easier
21
+ # to understand if we could write `attr*` methods in inline style.
11
22
  #
12
23
  # @safety
13
24
  # Autocorrection is not safe, because the visibility of dynamically
@@ -67,6 +78,34 @@ module RuboCop
67
78
  # private :bar, :baz
68
79
  #
69
80
  # end
81
+ #
82
+ # @example AllowModifiersOnAttrs: true (default)
83
+ # # good
84
+ # class Foo
85
+ #
86
+ # public attr_reader :bar
87
+ # protected attr_writer :baz
88
+ # private attr_accessor :qux
89
+ # private attr :quux
90
+ #
91
+ # def public_method; end
92
+ #
93
+ # private
94
+ #
95
+ # def private_method; end
96
+ #
97
+ # end
98
+ #
99
+ # @example AllowModifiersOnAttrs: false
100
+ # # bad
101
+ # class Foo
102
+ #
103
+ # public attr_reader :bar
104
+ # protected attr_writer :baz
105
+ # private attr_accessor :qux
106
+ # private attr :quux
107
+ #
108
+ # end
70
109
  class AccessModifierDeclarations < Base
71
110
  extend AutoCorrector
72
111
 
@@ -92,10 +131,17 @@ module RuboCop
92
131
  (send nil? {:private :protected :public :module_function} (sym _))
93
132
  PATTERN
94
133
 
134
+ # @!method access_modifier_with_attr?(node)
135
+ def_node_matcher :access_modifier_with_attr?, <<~PATTERN
136
+ (send nil? {:private :protected :public :module_function}
137
+ (send nil? {:attr :attr_reader :attr_writer :attr_accessor} _))
138
+ PATTERN
139
+
95
140
  def on_send(node)
96
141
  return unless node.access_modifier?
97
142
  return if ALLOWED_NODE_TYPES.include?(node.parent&.type)
98
143
  return if allow_modifiers_on_symbols?(node)
144
+ return if allow_modifiers_on_attrs?(node)
99
145
 
100
146
  if offense?(node)
101
147
  add_offense(node.loc.selector) do |corrector|
@@ -128,6 +174,10 @@ module RuboCop
128
174
  cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
129
175
  end
130
176
 
177
+ def allow_modifiers_on_attrs?(node)
178
+ cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node)
179
+ end
180
+
131
181
  def offense?(node)
132
182
  (group_style? && access_modifier_is_inlined?(node) &&
133
183
  !right_siblings_same_inline_method?(node)) ||
@@ -29,6 +29,8 @@ module RuboCop
29
29
  #
30
30
  # Names not on this list are likely to be meaningful and are allowed by default.
31
31
  #
32
+ # This cop handles not only method forwarding but also forwarding to `super`.
33
+ #
32
34
  # @example
33
35
  # # bad
34
36
  # def foo(*args, &block)
@@ -146,7 +148,7 @@ module RuboCop
146
148
 
147
149
  restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
148
150
  forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
149
- send_nodes = node.each_descendant(:send).to_a
151
+ send_nodes = node.each_descendant(:send, :csend, :super).to_a
150
152
 
151
153
  send_classifications = classify_send_nodes(
152
154
  node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
@@ -312,7 +314,8 @@ module RuboCop
312
314
  end
313
315
 
314
316
  def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
315
- return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
317
+ return if target_ruby_version <= 3.0 ||
318
+ block_arg.nil? || block_arg.source == '&' || explicit_block_name?
316
319
 
317
320
  add_offense(block_arg, message: BLOCK_MSG) do |corrector|
318
321
  add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
@@ -214,7 +214,7 @@ module RuboCop
214
214
  extend AutoCorrector
215
215
 
216
216
  MSG = 'Use the return of the conditional for variable assignment and comparison.'
217
- ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals'
217
+ ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
218
218
  VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
219
219
  ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
220
220
  LINE_LENGTH = 'Layout/LineLength'
@@ -58,12 +58,15 @@ module RuboCop
58
58
  end
59
59
 
60
60
  def verify_autocorrect_notice!
61
- raise Warning, AUTOCORRECT_EMPTY_WARNING if autocorrect_notice.empty?
61
+ if autocorrect_notice.nil? || autocorrect_notice.empty?
62
+ raise Warning, "#{cop_name}: #{AUTOCORRECT_EMPTY_WARNING}"
63
+ end
62
64
 
63
65
  regex = Regexp.new(notice)
64
- return if autocorrect_notice&.match?(regex)
66
+ return if autocorrect_notice.gsub(/^# */, '').match?(regex)
65
67
 
66
- raise Warning, "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
68
+ message = "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
69
+ raise Warning, "#{cop_name}: #{message}"
67
70
  end
68
71
 
69
72
  def insert_notice_before(processed_source)
@@ -77,26 +80,28 @@ module RuboCop
77
80
  return false if token_index >= processed_source.tokens.size
78
81
 
79
82
  token = processed_source.tokens[token_index]
80
- token.comment? && /^#!.*$/.match?(token.text)
83
+ token.comment? && /\A#!.*\z/.match?(token.text)
81
84
  end
82
85
 
83
86
  def encoding_token?(processed_source, token_index)
84
87
  return false if token_index >= processed_source.tokens.size
85
88
 
86
89
  token = processed_source.tokens[token_index]
87
- token.comment? && /^#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
90
+ token.comment? && /\A#.*coding\s?[:=]\s?(?:UTF|utf)-8/.match?(token.text)
88
91
  end
89
92
 
90
93
  def notice_found?(processed_source)
91
- notice_found = false
92
- notice_regexp = Regexp.new(notice)
94
+ notice_regexp = Regexp.new(notice.lines.map(&:strip).join)
95
+ multiline_notice = +''
93
96
  processed_source.tokens.each do |token|
94
97
  break unless token.comment?
95
98
 
96
- notice_found = notice_regexp.match?(token.text)
97
- break if notice_found
99
+ multiline_notice << token.text.sub(/\A# */, '')
100
+
101
+ break if notice_regexp.match?(token.text)
98
102
  end
99
- notice_found
103
+
104
+ multiline_notice.match?(notice_regexp)
100
105
  end
101
106
  end
102
107
  end
@@ -29,36 +29,36 @@ module RuboCop
29
29
  # end
30
30
  #
31
31
  # # allowed
32
- # # Class without body
32
+ # # Class without body
33
+ # class Person
34
+ # end
35
+ #
36
+ # # Namespace - A namespace can be a class or a module
37
+ # # Containing a class
38
+ # module Namespace
39
+ # # Description/Explanation of Person class
33
40
  # class Person
41
+ # # ...
34
42
  # end
43
+ # end
35
44
  #
36
- # # Namespace - A namespace can be a class or a module
37
- # # Containing a class
38
- # module Namespace
39
- # # Description/Explanation of Person class
40
- # class Person
41
- # # ...
42
- # end
45
+ # # Containing constant visibility declaration
46
+ # module Namespace
47
+ # class Private
43
48
  # end
44
49
  #
45
- # # Containing constant visibility declaration
46
- # module Namespace
47
- # class Private
48
- # end
49
- #
50
- # private_constant :Private
51
- # end
50
+ # private_constant :Private
51
+ # end
52
52
  #
53
- # # Containing constant definition
54
- # module Namespace
55
- # Public = Class.new
56
- # end
53
+ # # Containing constant definition
54
+ # module Namespace
55
+ # Public = Class.new
56
+ # end
57
57
  #
58
- # # Macro calls
59
- # module Namespace
60
- # extend Foo
61
- # end
58
+ # # Macro calls
59
+ # module Namespace
60
+ # extend Foo
61
+ # end
62
62
  #
63
63
  # @example AllowedConstants: ['ClassMethods']
64
64
  #
@@ -67,7 +67,7 @@ module RuboCop
67
67
  # module ClassMethods
68
68
  # # ...
69
69
  # end
70
- # end
70
+ # end
71
71
  #
72
72
  class Documentation < Base
73
73
  include DocumentationComment
@@ -95,6 +95,17 @@ module RuboCop
95
95
  # end
96
96
  # end
97
97
  #
98
+ # @example AllowedMethods: ['method_missing', 'respond_to_missing?']
99
+ #
100
+ # # good
101
+ # class Foo
102
+ # def method_missing(name, *args)
103
+ # end
104
+ #
105
+ # def respond_to_missing?(symbol, include_private)
106
+ # end
107
+ # end
108
+ #
98
109
  class DocumentationMethod < Base
99
110
  include DocumentationComment
100
111
  include DefNode
@@ -119,6 +130,7 @@ module RuboCop
119
130
  def check(node)
120
131
  return if non_public?(node) && !require_for_non_public_methods?
121
132
  return if documentation_comment?(node)
133
+ return if method_allowed?(node)
122
134
 
123
135
  add_offense(node)
124
136
  end
@@ -126,6 +138,14 @@ module RuboCop
126
138
  def require_for_non_public_methods?
127
139
  cop_config['RequireForNonPublicMethods']
128
140
  end
141
+
142
+ def method_allowed?(node)
143
+ allowed_methods.include?(node.method_name)
144
+ end
145
+
146
+ def allowed_methods
147
+ @allowed_methods ||= cop_config.fetch('AllowedMethods', []).map(&:to_sym)
148
+ end
129
149
  end
130
150
  end
131
151
  end
@@ -141,7 +141,7 @@ module RuboCop
141
141
  end
142
142
 
143
143
  def check_file(node, file_node)
144
- return true if special_file_keyword?(file_node)
144
+ return if special_file_keyword?(file_node)
145
145
 
146
146
  message = format(MSG_INCORRECT_FILE,
147
147
  method_name: node.method_name,
@@ -29,6 +29,8 @@ module RuboCop
29
29
  # * never - forces use of explicit hash literal value
30
30
  # * either - accepts both shorthand and explicit use of hash literal value
31
31
  # * consistent - forces use of the 3.1 syntax only if all values can be omitted in the hash
32
+ # * either_consistent - accepts both shorthand and explicit use of hash literal value,
33
+ # but they must be consistent
32
34
  #
33
35
  # @example EnforcedStyle: ruby19 (default)
34
36
  # # bad
@@ -110,6 +112,22 @@ module RuboCop
110
112
  # # good - can't omit `baz`
111
113
  # {foo: foo, bar: baz}
112
114
  #
115
+ # @example EnforcedShorthandSyntax: either_consistent
116
+ #
117
+ # # good - `foo` and `bar` values can be omitted, but they are consistent, so it's accepted
118
+ # {foo: foo, bar: bar}
119
+ #
120
+ # # bad - `bar` value can be omitted
121
+ # {foo:, bar: bar}
122
+ #
123
+ # # bad - mixed syntaxes
124
+ # {foo:, bar: baz}
125
+ #
126
+ # # good
127
+ # {foo:, bar:}
128
+ #
129
+ # # good - can't omit `baz`
130
+ # {foo: foo, bar: baz}
113
131
  class HashSyntax < Base
114
132
  include ConfigurableEnforcedStyle
115
133
  include HashShorthandSyntax
@@ -112,9 +112,11 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def message(node, keyword)
115
- message_template = node.elsif? ? MSG_FOR_ELSIF : MSG
116
-
117
- format(message_template, keyword: keyword)
115
+ if node.elsif?
116
+ MSG_FOR_ELSIF
117
+ else
118
+ format(MSG, keyword: keyword)
119
+ end
118
120
  end
119
121
 
120
122
  def return_boolean_value?(condition)
@@ -20,8 +20,8 @@ module RuboCop
20
20
  #
21
21
  # [source,ruby]
22
22
  # ----
23
- # @dest = []
24
- # src.each { |e| @dest << e * 2 } # `src` method may mutate `@dest`
23
+ # ret = []
24
+ # src.each { |e| ret << e * 2 } # `<<` method may mutate `ret`
25
25
  #
26
26
  # dest = []
27
27
  # src.each { |e| dest << transform(e, dest) } # `transform` method may mutate `dest`
@@ -57,7 +57,7 @@ module RuboCop
57
57
  def_node_matcher :each_block_with_push?, <<-PATTERN
58
58
  [
59
59
  ^({begin kwbegin} ...)
60
- ({block numblock} (send _ :each) _
60
+ ({block numblock} (send !{nil? self} :each) _
61
61
  (send (lvar _) {:<< :push :append} _))
62
62
  ]
63
63
  PATTERN
@@ -118,12 +118,14 @@ module RuboCop
118
118
 
119
119
  return unless numeric && operator && replacement_supported?(operator)
120
120
 
121
- [numeric, replacement(numeric, operator)]
121
+ [numeric, replacement(node, numeric, operator)]
122
122
  end
123
123
 
124
- def replacement(numeric, operation)
124
+ def replacement(node, numeric, operation)
125
125
  if style == :predicate
126
126
  [parenthesized_source(numeric), REPLACEMENTS.invert[operation.to_s]].join('.')
127
+ elsif negated?(node)
128
+ "(#{numeric.source} #{REPLACEMENTS[operation.to_s]} 0)"
127
129
  else
128
130
  [numeric.source, REPLACEMENTS[operation.to_s], 0].join(' ')
129
131
  end
@@ -157,6 +159,12 @@ module RuboCop
157
159
  end
158
160
  end
159
161
 
162
+ def negated?(node)
163
+ return false unless (parent = node.parent)
164
+
165
+ parent.send_type? && parent.method?(:!)
166
+ end
167
+
160
168
  # @!method predicate(node)
161
169
  def_node_matcher :predicate, <<~PATTERN
162
170
  (send $(...) ${:zero? :positive? :negative?})
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def always_multiline?
78
- @config.for_cop('Style/OneLineConditional')['AlwaysCorrectToMultiline']
78
+ cop_config['AlwaysCorrectToMultiline']
79
79
  end
80
80
 
81
81
  def cannot_replace_to_ternary?(node)
@@ -74,6 +74,7 @@ module RuboCop
74
74
  kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
75
75
  tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
76
76
  ].freeze
77
+ ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
77
78
 
78
79
  def on_new_investigation
79
80
  return unless processed_source.ast
@@ -137,7 +138,9 @@ module RuboCop
137
138
  # do_something \
138
139
  # argument
139
140
  def method_with_argument?(current_token, next_token)
140
- current_token.type == :tIDENTIFIER && ARGUMENT_TYPES.include?(next_token.type)
141
+ return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
142
+
143
+ ARGUMENT_TYPES.include?(next_token.type)
141
144
  end
142
145
 
143
146
  # rubocop:disable Metrics/AbcSize
@@ -131,7 +131,7 @@ module RuboCop
131
131
  end
132
132
 
133
133
  def in_same_section?(node1, node2)
134
- !node1.source_range.with(end_pos: node2.source_range.end_pos).source.include?("\n\n")
134
+ !node1.source_range.join(node2.source_range.end).source.include?("\n\n")
135
135
  end
136
136
  end
137
137
  end
@@ -7,12 +7,12 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # Foo.send(:bar)
11
- # quuz.send(:fred)
10
+ # Foo.send(bar)
11
+ # quuz.send(fred)
12
12
  #
13
13
  # # good
14
- # Foo.__send__(:bar)
15
- # quuz.public_send(:fred)
14
+ # Foo.__send__(bar)
15
+ # quuz.public_send(fred)
16
16
  class Send < Base
17
17
  MSG = 'Prefer `Object#__send__` or `Object#public_send` to `send`.'
18
18
  RESTRICT_ON_SEND = %i[send].freeze
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Detects the use of the `public_send` method with a literal method name argument.
7
+ # Since the `send` method can be used to call private methods, by default,
8
+ # only the `public_send` method is detected.
9
+ #
10
+ # @safety
11
+ # This cop is not safe because it can incorrectly detect based on the receiver.
12
+ # Additionally, when `AllowSend` is set to `true`, it cannot determine whether
13
+ # the `send` method being detected is calling a private method.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # obj.public_send(:method_name)
18
+ # obj.public_send('method_name')
19
+ #
20
+ # # good
21
+ # obj.method_name
22
+ #
23
+ # @example AllowSend: true (default)
24
+ # # good
25
+ # obj.send(:method_name)
26
+ # obj.send('method_name')
27
+ # obj.__send__(:method_name)
28
+ # obj.__send__('method_name')
29
+ #
30
+ # @example AllowSend: false
31
+ # # bad
32
+ # obj.send(:method_name)
33
+ # obj.send('method_name')
34
+ # obj.__send__(:method_name)
35
+ # obj.__send__('method_name')
36
+ #
37
+ # # good
38
+ # obj.method_name
39
+ #
40
+ class SendWithLiteralMethodName < Base
41
+ extend AutoCorrector
42
+
43
+ MSG = 'Use `%<method_name>s` method call directly instead.'
44
+ RESTRICT_ON_SEND = %i[public_send send __send__].freeze
45
+ STATIC_METHOD_NAME_NODE_TYPES = %i[sym str].freeze
46
+ METHOD_NAME_PATTERN = /\A[a-zA-Z_][a-zA-Z0-9_]*[!?=]?\z/.freeze
47
+ RESERVED_WORDS = %i[
48
+ BEGIN END alias and begin break case class def defined? do else elsif end ensure
49
+ false for if in module next nil not or redo rescue retry return self super then true
50
+ undef unless until when while yield
51
+ ].freeze
52
+
53
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
54
+ def on_send(node)
55
+ return if allow_send? && !node.method?(:public_send)
56
+ return unless (first_argument = node.first_argument)
57
+ return unless STATIC_METHOD_NAME_NODE_TYPES.include?(first_argument.type)
58
+
59
+ offense_range = offense_range(node)
60
+ method_name = first_argument.value
61
+ return if !METHOD_NAME_PATTERN.match?(method_name) || RESERVED_WORDS.include?(method_name)
62
+
63
+ add_offense(offense_range, message: format(MSG, method_name: method_name)) do |corrector|
64
+ if node.arguments.one?
65
+ corrector.replace(offense_range, method_name)
66
+ else
67
+ corrector.replace(node.loc.selector, method_name)
68
+ corrector.remove(removal_argument_range(first_argument, node.arguments[1]))
69
+ end
70
+ end
71
+ end
72
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
73
+
74
+ private
75
+
76
+ def allow_send?
77
+ !!cop_config['AllowSend']
78
+ end
79
+
80
+ def offense_range(node)
81
+ node.loc.selector.join(node.source_range.end)
82
+ end
83
+
84
+ def removal_argument_range(first_argument, second_argument)
85
+ first_argument.source_range.begin.join(second_argument.source_range.begin)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -58,9 +58,8 @@ module RuboCop
58
58
  #
59
59
  # @example EnforcedStyle: use_builtin_english_names
60
60
  #
61
- # Like `use_perl_names` but allows builtin global vars.
62
- #
63
61
  # # good
62
+ # # Like `use_perl_names` but allows builtin global vars.
64
63
  # puts $LOAD_PATH
65
64
  # puts $LOADED_FEATURES
66
65
  # puts $PROGRAM_NAME