rubocop 0.77.0 → 0.79.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +39 -26
  4. data/lib/rubocop.rb +11 -2
  5. data/lib/rubocop/ast/builder.rb +43 -42
  6. data/lib/rubocop/ast/node/def_node.rb +11 -0
  7. data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
  8. data/lib/rubocop/ast/traversal.rb +11 -3
  9. data/lib/rubocop/cli/command/auto_genenerate_config.rb +7 -7
  10. data/lib/rubocop/cli/command/show_cops.rb +11 -4
  11. data/lib/rubocop/config.rb +1 -1
  12. data/lib/rubocop/config_loader.rb +19 -19
  13. data/lib/rubocop/config_obsoletion.rb +3 -3
  14. data/lib/rubocop/config_validator.rb +55 -95
  15. data/lib/rubocop/cop/autocorrect_logic.rb +7 -4
  16. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +2 -2
  17. data/lib/rubocop/cop/cop.rb +3 -1
  18. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  19. data/lib/rubocop/cop/generator.rb +3 -4
  20. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  21. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -2
  22. data/lib/rubocop/cop/layout/hash_alignment.rb +8 -4
  23. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -4
  24. data/lib/rubocop/cop/{metrics → layout}/line_length.rb +5 -78
  25. data/lib/rubocop/cop/layout/multiline_block_layout.rb +14 -5
  26. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -6
  27. data/lib/rubocop/cop/layout/space_before_block_braces.rb +17 -0
  28. data/lib/rubocop/cop/lint/debugger.rb +2 -2
  29. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  30. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +89 -0
  31. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +3 -3
  32. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +4 -4
  33. data/lib/rubocop/cop/migration/department_name.rb +16 -1
  34. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  35. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -7
  36. data/lib/rubocop/cop/mixin/line_length_help.rb +88 -0
  37. data/lib/rubocop/cop/mixin/rational_literal.rb +18 -0
  38. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  39. data/lib/rubocop/cop/mixin/trailing_comma.rb +6 -3
  40. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  41. data/lib/rubocop/cop/offense.rb +11 -0
  42. data/lib/rubocop/cop/registry.rb +7 -2
  43. data/lib/rubocop/cop/style/attr.rb +8 -0
  44. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  45. data/lib/rubocop/cop/style/guard_clause.rb +3 -2
  46. data/lib/rubocop/cop/style/if_unless_modifier.rb +38 -3
  47. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  48. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +4 -207
  49. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +168 -0
  50. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
  51. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
  52. data/lib/rubocop/cop/style/multiline_when_then.rb +5 -1
  53. data/lib/rubocop/cop/style/numeric_predicate.rb +4 -3
  54. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
  55. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -1
  56. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  57. data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
  58. data/lib/rubocop/formatter/base_formatter.rb +2 -2
  59. data/lib/rubocop/formatter/json_formatter.rb +6 -5
  60. data/lib/rubocop/node_pattern.rb +1 -1
  61. data/lib/rubocop/options.rb +8 -8
  62. data/lib/rubocop/result_cache.rb +2 -0
  63. data/lib/rubocop/rspec/shared_contexts.rb +5 -0
  64. data/lib/rubocop/runner.rb +5 -1
  65. data/lib/rubocop/target_ruby.rb +151 -0
  66. data/lib/rubocop/version.rb +1 -1
  67. metadata +12 -5
@@ -8,9 +8,9 @@ module RuboCop
8
8
  # In Ruby 2.3 or newer, squiggly heredocs (`<<~`) should be used. If you
9
9
  # use the older rubies, you should introduce some library to your project
10
10
  # (e.g. ActiveSupport, Powerpack or Unindent).
11
- # Note: When `Metrics/LineLength`'s `AllowHeredoc` is false (not default),
11
+ # Note: When `Layout/LineLength`'s `AllowHeredoc` is false (not default),
12
12
  # this cop does not add any offenses for long here documents to
13
- # avoid `Metrics/LineLength`'s offenses.
13
+ # avoid `Layout/LineLength`'s offenses.
14
14
  #
15
15
  # @example EnforcedStyle: squiggly (default)
16
16
  # # bad
@@ -159,11 +159,11 @@ module RuboCop
159
159
  end
160
160
 
161
161
  def unlimited_heredoc_length?
162
- config.for_cop('Metrics/LineLength')['AllowHeredoc']
162
+ config.for_cop('Layout/LineLength')['AllowHeredoc']
163
163
  end
164
164
 
165
165
  def max_line_length
166
- config.for_cop('Metrics/LineLength')['Max']
166
+ config.for_cop('Layout/LineLength')['Max']
167
167
  end
168
168
 
169
169
  def correct_by_squiggly(node)
@@ -2,10 +2,9 @@
2
2
 
3
3
  require 'uri'
4
4
 
5
- # rubocop:disable Metrics/ClassLength
6
5
  module RuboCop
7
6
  module Cop
8
- module Metrics
7
+ module Layout
9
8
  # This cop checks the length of lines in the source code.
10
9
  # The maximum length is configurable.
11
10
  # The tab size is configured in the `IndentationWidth`
@@ -58,6 +57,7 @@ module RuboCop
58
57
  include ConfigurableMax
59
58
  include IgnoredPattern
60
59
  include RangeHelp
60
+ include LineLengthHelp
61
61
 
62
62
  MSG = 'Line is too long. [%<length>d/%<max>d]'
63
63
 
@@ -130,20 +130,6 @@ module RuboCop
130
130
  @heredocs ||= extract_heredocs(processed_source.ast)
131
131
  end
132
132
 
133
- def tab_indentation_width
134
- config.for_cop('Layout/Tab')['IndentationWidth']
135
- end
136
-
137
- def indentation_difference(line)
138
- return 0 unless tab_indentation_width
139
-
140
- line.match(/^\t*/)[0].size * (tab_indentation_width - 1)
141
- end
142
-
143
- def line_length(line)
144
- line.length + indentation_difference(line)
145
- end
146
-
147
133
  def highlight_start(line)
148
134
  max - indentation_difference(line)
149
135
  end
@@ -225,51 +211,10 @@ module RuboCop
225
211
  end
226
212
  end
227
213
 
228
- def allow_uri?
229
- cop_config['AllowURI']
230
- end
231
-
232
- def ignore_cop_directives?
233
- cop_config['IgnoreCopDirectives']
234
- end
235
-
236
- def allowed_uri_position?(line, uri_range)
237
- uri_range.begin < max &&
238
- (uri_range.end == line_length(line) ||
239
- uri_range.end == line_length(line) - 1)
240
- end
241
-
242
- def find_excessive_uri_range(line)
243
- last_uri_match = match_uris(line).last
244
- return nil unless last_uri_match
245
-
246
- begin_position, end_position =
247
- last_uri_match.offset(0).map do |pos|
248
- pos + indentation_difference(line)
249
- end
250
- return nil if begin_position < max && end_position < max
251
-
252
- begin_position...end_position
253
- end
254
-
255
- def match_uris(string)
256
- matches = []
257
- string.scan(uri_regexp) do
258
- matches << $LAST_MATCH_INFO if valid_uri?($LAST_MATCH_INFO[0])
214
+ def line_in_heredoc?(line_number)
215
+ heredocs.any? do |range, _delimiter|
216
+ range.cover?(line_number)
259
217
  end
260
- matches
261
- end
262
-
263
- def valid_uri?(uri_ish_string)
264
- URI.parse(uri_ish_string)
265
- true
266
- rescue URI::InvalidURIError, NoMethodError
267
- false
268
- end
269
-
270
- def uri_regexp
271
- @uri_regexp ||=
272
- URI::DEFAULT_PARSER.make_regexp(cop_config['URISchemes'])
273
218
  end
274
219
 
275
220
  def check_directive_line(line, line_index)
@@ -287,23 +232,6 @@ module RuboCop
287
232
  )
288
233
  end
289
234
 
290
- def directive_on_source_line?(line_index)
291
- source_line_number = line_index + processed_source.buffer.first_line
292
- comment =
293
- processed_source
294
- .comments
295
- .detect { |e| e.location.line == source_line_number }
296
-
297
- return false unless comment
298
-
299
- comment.text.match(CommentConfig::COMMENT_DIRECTIVE_REGEXP)
300
- end
301
-
302
- def line_length_without_directive(line)
303
- before_comment, = line.split(CommentConfig::COMMENT_DIRECTIVE_REGEXP)
304
- before_comment.rstrip.length
305
- end
306
-
307
235
  def check_uri_line(line, line_index)
308
236
  uri_range = find_excessive_uri_range(line)
309
237
  return if uri_range && allowed_uri_position?(line, uri_range)
@@ -318,4 +246,3 @@ module RuboCop
318
246
  end
319
247
  end
320
248
  end
321
- # rubocop:enable Metrics/ClassLength
@@ -97,7 +97,8 @@ module RuboCop
97
97
  def line_break_necessary_in_args?(node)
98
98
  needed_length = node.source_range.column +
99
99
  node.source.lines.first.length +
100
- block_arg_string(node.arguments).length + PIPE_SIZE
100
+ block_arg_string(node, node.arguments).length +
101
+ PIPE_SIZE
101
102
  needed_length > max_line_length
102
103
  end
103
104
 
@@ -115,7 +116,8 @@ module RuboCop
115
116
  newlines: false
116
117
  ).end_pos
117
118
  range = range_between(node.loc.begin.end.begin_pos, end_pos)
118
- corrector.replace(range, " |#{block_arg_string(node.arguments)}|")
119
+ corrector.replace(range,
120
+ " |#{block_arg_string(node, node.arguments)}|")
119
121
  end
120
122
 
121
123
  def autocorrect_body(corrector, node, block_body)
@@ -131,14 +133,21 @@ module RuboCop
131
133
  "\n #{' ' * block_start_col}")
132
134
  end
133
135
 
134
- def block_arg_string(args)
135
- args.children.map do |arg|
136
+ def block_arg_string(node, args)
137
+ arg_string = args.children.map do |arg|
136
138
  if arg.mlhs_type?
137
- "(#{block_arg_string(arg)})"
139
+ "(#{block_arg_string(node, arg)})"
138
140
  else
139
141
  arg.source
140
142
  end
141
143
  end.join(', ')
144
+ arg_string += ',' if include_trailing_comma?(node.arguments)
145
+ arg_string
146
+ end
147
+
148
+ def include_trailing_comma?(args)
149
+ arg_count = args.each_descendant(:arg).to_a.size
150
+ arg_count == 1 && args.source.include?(',')
142
151
  end
143
152
  end
144
153
  end
@@ -3,24 +3,37 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Checks that operators have space around them, except for **
7
- # which should not have surrounding space.
6
+ # Checks that operators have space around them, except for ** which
7
+ # should or shouldn't have surrounding space depending on configuration.
8
8
  #
9
9
  # @example
10
10
  # # bad
11
11
  # total = 3*4
12
12
  # "apple"+"juice"
13
13
  # my_number = 38/4
14
- # a ** b
15
14
  #
16
15
  # # good
17
16
  # total = 3 * 4
18
17
  # "apple" + "juice"
19
18
  # my_number = 38 / 4
19
+ #
20
+ # @example EnforcedStyleForExponentOperator: no_space (default)
21
+ # # bad
22
+ # a ** b
23
+ #
24
+ # # good
25
+ # a**b
26
+ #
27
+ # @example EnforcedStyleForExponentOperator: space
28
+ # # bad
20
29
  # a**b
30
+ #
31
+ # # good
32
+ # a ** b
21
33
  class SpaceAroundOperators < Cop
22
34
  include PrecedingFollowingAlignment
23
35
  include RangeHelp
36
+ include RationalLiteral
24
37
 
25
38
  IRREGULAR_METHODS = %i[[] ! []=].freeze
26
39
  EXCESSIVE_SPACE = ' '
@@ -53,6 +66,8 @@ module RuboCop
53
66
  end
54
67
 
55
68
  def on_send(node)
69
+ return if rational_literal?(node)
70
+
56
71
  if node.setter_method?
57
72
  on_special_asgn(node)
58
73
  elsif regular_operator?(node)
@@ -101,7 +116,7 @@ module RuboCop
101
116
 
102
117
  def autocorrect(range)
103
118
  lambda do |corrector|
104
- if range.source =~ /\*\*/
119
+ if range.source =~ /\*\*/ && !space_around_exponent_operator?
105
120
  corrector.replace(range, '**')
106
121
  elsif range.source.end_with?("\n")
107
122
  corrector.replace(range, " #{range.source.strip}\n")
@@ -138,8 +153,10 @@ module RuboCop
138
153
  end
139
154
 
140
155
  def offense_message(type, operator, with_space, right_operand)
141
- if operator.is?('**')
142
- 'Space around operator `**` detected.' unless with_space.is?('**')
156
+ if should_not_have_surrounding_space?(operator)
157
+ return if with_space.is?(operator.source)
158
+
159
+ "Space around operator `#{operator.source}` detected."
143
160
  elsif with_space.source !~ /^\s.*\s$/
144
161
  "Surrounding space missing for operator `#{operator.source}`."
145
162
  elsif excess_leading_space?(type, operator, with_space) ||
@@ -176,6 +193,14 @@ module RuboCop
176
193
  align_hash_cop_config &&
177
194
  align_hash_cop_config['EnforcedHashRocketStyle'] == 'table'
178
195
  end
196
+
197
+ def space_around_exponent_operator?
198
+ cop_config['EnforcedStyleForExponentOperator'] == 'space'
199
+ end
200
+
201
+ def should_not_have_surrounding_space?(operator)
202
+ operator.is?('**') ? !space_around_exponent_operator? : false
203
+ end
179
204
  end
180
205
  end
181
206
  end
@@ -41,6 +41,14 @@ module RuboCop
41
41
  def on_block(node)
42
42
  return if node.keywords?
43
43
 
44
+ # Do not register an offense for multi-line braces when specifying
45
+ # `EnforcedStyle: no_space`. It will conflict with auto-correction
46
+ # by `EnforcedStyle: line_count_based` of `Style/BlockDelimiters` cop.
47
+ # That means preventing auto-correction to incorrect auto-corrected
48
+ # code.
49
+ # See: https://github.com/rubocop-hq/rubocop/issues/7534
50
+ return if conflict_with_block_delimiters?(node)
51
+
44
52
  left_brace = node.loc.begin
45
53
  space_plus_brace = range_with_surrounding_space(range: left_brace)
46
54
  used_style =
@@ -110,6 +118,15 @@ module RuboCop
110
118
  end
111
119
  end
112
120
 
121
+ def conflict_with_block_delimiters?(node)
122
+ block_delimiters_style == 'line_count_based' &&
123
+ style == :no_space && node.multiline?
124
+ end
125
+
126
+ def block_delimiters_style
127
+ config.for_cop('Style/BlockDelimiters')['EnforcedStyle']
128
+ end
129
+
113
130
  def empty_braces?(loc)
114
131
  loc.begin.end_pos == loc.end.begin_pos
115
132
  end
@@ -43,9 +43,9 @@ module RuboCop
43
43
  PATTERN
44
44
 
45
45
  def_node_matcher :debugger_call?, <<~PATTERN
46
- {(send {nil? #kernel?} {:debugger :byebug :remote_byebug} ...)
46
+ {(send {nil? #kernel?} {:debugger :byebug :remote_byebug :console} ...)
47
47
  (send (send {#kernel? nil?} :binding)
48
- {:pry :remote_pry :pry_remote} ...)
48
+ {:pry :remote_pry :pry_remote :console} ...)
49
49
  (send (const {nil? (cbase)} :Pry) :rescue ...)
50
50
  (send nil? {:save_and_open_page
51
51
  :save_and_open_screenshot
@@ -22,7 +22,7 @@ module RuboCop
22
22
  # num = 0
23
23
  # sum = numbers.each_with_object(num) { |e, a| a += e }
24
24
  class EachWithObjectArgument < Cop
25
- MSG = 'The argument to each_with_object can not be immutable.'
25
+ MSG = 'The argument to each_with_object cannot be immutable.'
26
26
 
27
27
  def_node_matcher :each_with_object?, <<~PATTERN
28
28
  ({send csend} _ :each_with_object $_)
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # `Dir[...]` and `Dir.glob(...)` do not make any guarantees about
7
+ # the order in which files are returned. The final order is
8
+ # determined by the operating system and file system.
9
+ # This means that using them in cases where the order matters,
10
+ # such as requiring files, can lead to intermittent failures
11
+ # that are hard to debug. To ensure this doesn't happen,
12
+ # always sort the list.
13
+ #
14
+ # @example
15
+ #
16
+ # # bad
17
+ # Dir["./lib/**/*.rb"].each do |file|
18
+ # require file
19
+ # end
20
+ #
21
+ # # good
22
+ # Dir["./lib/**/*.rb"].sort.each do |file|
23
+ # require file
24
+ # end
25
+ #
26
+ # @example
27
+ #
28
+ # # bad
29
+ # Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')) do |file|
30
+ # require file
31
+ # end
32
+ #
33
+ # # good
34
+ # Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')).sort.each do |file|
35
+ # require file
36
+ # end
37
+ #
38
+ class NonDeterministicRequireOrder < Cop
39
+ MSG = 'Sort files before requiring them.'
40
+
41
+ def on_block(node)
42
+ return unless node.body
43
+ return unless unsorted_dir_loop?(node.send_node)
44
+
45
+ loop_variable(node.arguments) do |var_name|
46
+ return unless var_is_required?(node.body, var_name)
47
+
48
+ add_offense(node.send_node)
49
+ end
50
+ end
51
+
52
+ def autocorrect(node)
53
+ if unsorted_dir_block?(node)
54
+ lambda do |corrector|
55
+ corrector.replace(node.loc.expression, "#{node.source}.sort.each")
56
+ end
57
+ else
58
+ lambda do |corrector|
59
+ source = node.receiver.source
60
+ corrector.replace(node.loc.expression, "#{source}.sort.each")
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def unsorted_dir_loop?(node)
68
+ unsorted_dir_block?(node) || unsorted_dir_each?(node)
69
+ end
70
+
71
+ def_node_matcher :unsorted_dir_block?, <<~PATTERN
72
+ (send (const nil? :Dir) :glob ...)
73
+ PATTERN
74
+
75
+ def_node_matcher :unsorted_dir_each?, <<~PATTERN
76
+ (send (send (const nil? :Dir) {:[] :glob} ...) :each)
77
+ PATTERN
78
+
79
+ def_node_matcher :loop_variable, <<~PATTERN
80
+ (args (arg $_))
81
+ PATTERN
82
+
83
+ def_node_search :var_is_required?, <<~PATTERN
84
+ (send nil? :require (lvar %1))
85
+ PATTERN
86
+ end
87
+ end
88
+ end
89
+ end
@@ -19,9 +19,9 @@ module RuboCop
19
19
  #
20
20
  # @example
21
21
  # # bad
22
- # # rubocop:disable Metrics/LineLength
22
+ # # rubocop:disable Layout/LineLength
23
23
  # x += 1
24
- # # rubocop:enable Metrics/LineLength
24
+ # # rubocop:enable Layout/LineLength
25
25
  #
26
26
  # # good
27
27
  # x += 1
@@ -213,7 +213,7 @@ module RuboCop
213
213
  end
214
214
 
215
215
  def matching_range(haystack, needle)
216
- offset = (haystack.source =~ Regexp.new(Regexp.escape(needle)))
216
+ offset = haystack.source.index(needle)
217
217
  return unless offset
218
218
 
219
219
  offset += haystack.begin_pos
@@ -15,20 +15,20 @@ module RuboCop
15
15
  # @example
16
16
  # # bad
17
17
  # foo = 1
18
- # # rubocop:enable Metrics/LineLength
18
+ # # rubocop:enable Layout/LineLength
19
19
  #
20
20
  # # good
21
21
  # foo = 1
22
22
  # @example
23
23
  # # bad
24
- # # rubocop:disable Metrics/LineLength
24
+ # # rubocop:disable Layout/LineLength
25
25
  # baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrrr
26
- # # rubocop:enable Metrics/LineLength
26
+ # # rubocop:enable Layout/LineLength
27
27
  # baz
28
28
  # # rubocop:enable all
29
29
  #
30
30
  # # good
31
- # # rubocop:disable Metrics/LineLength
31
+ # # rubocop:disable Layout/LineLength
32
32
  # baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrrr
33
33
  # # rubocop:enable all
34
34
  # baz