rubocop 1.92.0 → 1.92.2

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +1 -0
  3. data/lib/rubocop/config.rb +0 -4
  4. data/lib/rubocop/config_obsoletion.rb +9 -0
  5. data/lib/rubocop/cop/badge.rb +1 -1
  6. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +16 -1
  7. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  8. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
  9. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
  10. data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
  11. data/lib/rubocop/cop/layout/class_structure.rb +21 -7
  12. data/lib/rubocop/cop/layout/dot_position.rb +25 -15
  13. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +11 -7
  14. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  15. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
  16. data/lib/rubocop/cop/layout/end_alignment.rb +5 -15
  17. data/lib/rubocop/cop/layout/extra_spacing.rb +18 -7
  18. data/lib/rubocop/cop/layout/first_argument_indentation.rb +26 -1
  19. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
  20. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +11 -5
  21. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +5 -3
  22. data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
  23. data/lib/rubocop/cop/layout/line_length.rb +127 -11
  24. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -4
  25. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +16 -5
  26. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/single_line_block_chain.rb +3 -3
  28. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
  29. data/lib/rubocop/cop/layout/space_before_block_braces.rb +12 -0
  30. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
  31. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
  32. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
  33. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
  34. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
  35. data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
  36. data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
  37. data/lib/rubocop/cop/lint/number_conversion.rb +2 -0
  38. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
  39. data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
  40. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -8
  41. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
  42. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
  43. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
  44. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  45. data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -6
  46. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +3 -1
  47. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  48. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +36 -0
  49. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -5
  50. data/lib/rubocop/cop/mixin/statement_modifier.rb +17 -3
  51. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  52. data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
  53. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  54. data/lib/rubocop/cop/style/access_modifier_declarations.rb +30 -2
  55. data/lib/rubocop/cop/style/and_or.rb +34 -11
  56. data/lib/rubocop/cop/style/arguments_forwarding.rb +28 -2
  57. data/lib/rubocop/cop/style/block_delimiters.rb +6 -0
  58. data/lib/rubocop/cop/style/case_equality.rb +14 -3
  59. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  60. data/lib/rubocop/cop/style/class_methods_definitions.rb +7 -0
  61. data/lib/rubocop/cop/style/collection_querying.rb +79 -46
  62. data/lib/rubocop/cop/style/combinable_loops.rb +4 -0
  63. data/lib/rubocop/cop/style/concat_array_literals.rb +13 -1
  64. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
  65. data/lib/rubocop/cop/style/endless_method.rb +38 -6
  66. data/lib/rubocop/cop/style/float_division.rb +16 -1
  67. data/lib/rubocop/cop/style/for.rb +14 -1
  68. data/lib/rubocop/cop/style/guard_clause.rb +22 -21
  69. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
  70. data/lib/rubocop/cop/style/hash_lookup_method.rb +10 -0
  71. data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -12
  72. data/lib/rubocop/cop/style/it_block_parameter.rb +63 -2
  73. data/lib/rubocop/cop/style/lambda.rb +16 -1
  74. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +36 -4
  75. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -0
  76. data/lib/rubocop/cop/style/method_def_parentheses.rb +9 -1
  77. data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
  78. data/lib/rubocop/cop/style/mutable_constant.rb +25 -7
  79. data/lib/rubocop/cop/style/numeric_predicate.rb +7 -0
  80. data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
  81. data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
  82. data/lib/rubocop/cop/style/raise_args.rb +80 -11
  83. data/lib/rubocop/cop/style/reduce_to_hash.rb +32 -34
  84. data/lib/rubocop/cop/style/redundant_begin.rb +26 -3
  85. data/lib/rubocop/cop/style/redundant_exception.rb +13 -9
  86. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -2
  87. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
  88. data/lib/rubocop/cop/style/redundant_self.rb +9 -1
  89. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
  90. data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
  91. data/lib/rubocop/cop/style/require_order.rb +16 -8
  92. data/lib/rubocop/cop/style/rescue_modifier.rb +6 -0
  93. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
  94. data/lib/rubocop/cop/style/single_line_methods.rb +26 -0
  95. data/lib/rubocop/cop/style/string_concatenation.rb +12 -1
  96. data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
  97. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  98. data/lib/rubocop/lsp/routes.rb +23 -23
  99. data/lib/rubocop/plugin/configuration_integrator.rb +24 -3
  100. data/lib/rubocop/runner.rb +1 -1
  101. data/lib/rubocop/server/cache.rb +4 -4
  102. data/lib/rubocop/target_ruby.rb +21 -9
  103. data/lib/rubocop/version.rb +1 -1
  104. metadata +2 -2
@@ -69,15 +69,41 @@ module RuboCop
69
69
  return false if disallow_endless_method_style?
70
70
  return false unless body_node
71
71
  return false if body_node.parent.assignment_method?
72
+ return false if captures_following_code?(body_node.parent)
72
73
 
73
74
  !unsupported_endless_method_body?(body_node) && endless_method_body?(body_node)
74
75
  end
75
76
 
77
+ # `def foo; bar; end && baz` would become `def foo() = bar && baz`. The same goes for a def
78
+ # that ends an operand, as in `a && def foo; bar; end || baz`.
79
+ def captures_following_code?(node)
80
+ return false unless (parent = node.parent)
81
+
82
+ node_end = node.source_range.end_pos
83
+ return captures_following_code?(parent) if parent.source_range.end_pos == node_end
84
+
85
+ parent.children.first.equal?(node) && extends_endless_body?(parent, node)
86
+ end
87
+
88
+ def extends_endless_body?(parent, node)
89
+ case parent.type
90
+ when :and, :or then parent.logical_operator?
91
+ when :if then parent.ternary?
92
+ when :rescue then same_line?(node, parent.resbody_branches.first) # the modifier form
93
+ else parent.type?(:call, :range)
94
+ end
95
+ end
96
+
76
97
  def unsupported_endless_method_body?(body_node)
77
98
  body_node.basic_conditional? ||
78
99
  NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
79
100
  end
80
101
 
102
+ # The body gets parenthesized when it becomes endless, so it is no longer a command.
103
+ def command_body_in_argument?(body)
104
+ !require_parentheses?(body) && super
105
+ end
106
+
81
107
  def correct_to_multiline(corrector, node)
82
108
  if (body = node.body) && body.begin_type? && body.parenthesized_call?
83
109
  break_line_before(corrector, node, body)
@@ -143,7 +143,18 @@ module RuboCop
143
143
  def replacement(parts)
144
144
  interpolated_parts = parts.map { |part| adjust_str(part) }
145
145
 
146
- "\"#{handle_quotes(interpolated_parts).join}\""
146
+ "\"#{join_parts(handle_quotes(interpolated_parts))}\""
147
+ end
148
+
149
+ def join_parts(parts)
150
+ parts.each_with_object(+'') do |part, result|
151
+ result.insert(-2, '\\') if interpolation_formed?(result, part)
152
+ result << part
153
+ end
154
+ end
155
+
156
+ def interpolation_formed?(preceding, part)
157
+ part.start_with?('{', '@', '$') && preceding.match?(/(?<!\\)(?:\\\\)*#\z/)
147
158
  end
148
159
 
149
160
  def adjust_str(part)
@@ -41,6 +41,12 @@ module RuboCop
41
41
  MSG = "Don't extend an instance initialized by `Struct.new`. " \
42
42
  'Use a block to customize the struct.'
43
43
 
44
+ # When the closing parenthesis of `Struct.new` is on its own line, omitting the
45
+ # parentheses in the same pass leaves a line break before the appended `do`.
46
+ def self.autocorrect_incompatible_with
47
+ [Style::MethodCallWithArgsParentheses]
48
+ end
49
+
44
50
  def on_class(node)
45
51
  return unless struct_constructor?(node.parent_class)
46
52
  return if defines_constants?(node.body)
@@ -166,7 +166,7 @@ module RuboCop
166
166
  PATTERN
167
167
 
168
168
  def self.autocorrect_incompatible_with
169
- [Layout::SpaceBeforeBlockBraces]
169
+ [Layout::SpaceBeforeBlockBraces, Style::TrailingCommaInArguments]
170
170
  end
171
171
 
172
172
  # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -25,12 +25,6 @@ module RuboCop
25
25
  # via `executeCommandProvider` so it knows which commands it can invoke.
26
26
  EXECUTE_COMMANDS = %w[rubocop.formatAutocorrects rubocop.formatAutocorrectsAll].freeze
27
27
 
28
- def self.handle(name, &block)
29
- define_method(:"handle_#{name}", &block)
30
- end
31
-
32
- private_class_method :handle
33
-
34
28
  def initialize(server)
35
29
  @server = server
36
30
 
@@ -44,6 +38,29 @@ module RuboCop
44
38
  method(name)
45
39
  end
46
40
 
41
+ def handle_unsupported_method(request, method = request[:method])
42
+ @server.write(
43
+ id: request[:id],
44
+ error: LanguageServer::Protocol::Interface::ResponseError.new(
45
+ code: LanguageServer::Protocol::Constant::ErrorCodes::METHOD_NOT_FOUND,
46
+ message: "Unsupported Method: #{method}"
47
+ )
48
+ )
49
+ Logger.log("Unsupported Method: #{method}")
50
+ end
51
+
52
+ def handle_method_missing(request)
53
+ return unless request.key?(:id)
54
+
55
+ @server.write(id: request[:id], result: nil)
56
+ end
57
+
58
+ def self.handle(name, &block)
59
+ define_method(:"handle_#{name}", &block)
60
+ end
61
+
62
+ private_class_method :handle
63
+
47
64
  handle 'initialize' do |request|
48
65
  initialization_options = extract_initialization_options_from(request)
49
66
 
@@ -178,23 +195,6 @@ module RuboCop
178
195
  # No-op, we log everything
179
196
  end
180
197
 
181
- def handle_unsupported_method(request, method = request[:method])
182
- @server.write(
183
- id: request[:id],
184
- error: LanguageServer::Protocol::Interface::ResponseError.new(
185
- code: LanguageServer::Protocol::Constant::ErrorCodes::METHOD_NOT_FOUND,
186
- message: "Unsupported Method: #{method}"
187
- )
188
- )
189
- Logger.log("Unsupported Method: #{method}")
190
- end
191
-
192
- def handle_method_missing(request)
193
- return unless request.key?(:id)
194
-
195
- @server.write(id: request[:id], result: nil)
196
- end
197
-
198
198
  private
199
199
 
200
200
  def extract_initialization_options_from(request)
@@ -105,18 +105,39 @@ module RuboCop
105
105
 
106
106
  case rules.type
107
107
  when :path
108
- [ConfigLoader.load_file(rules.value, check: false), rules.value]
108
+ config = ConfigLoader.load_file(rules.value, check: false)
109
+ warn_about_obsolete_config(plugin, config)
110
+ [config, rules.value]
109
111
  when :object
110
112
  path = plugin.method(:rules).source_location[0]
111
113
  [Config.create(rules.value, path, check: true), path]
112
114
  when :error
113
- plugin_name = plugin.about&.name || plugin.inspect
114
115
  error_message = rules.value.respond_to?(:message) ? rules.value.message : rules.value
115
116
 
116
- raise "Plugin `#{plugin_name}' failed to load with error: #{error_message}"
117
+ raise "Plugin `#{plugin_name(plugin)}' failed to load with error: #{error_message}"
117
118
  end
118
119
  end
119
120
 
121
+ # Plugin configuration is loaded without validation, so an obsolete key in a plugin's
122
+ # defaults used to surface only later, against the user's own file, once the two had
123
+ # been merged. Report it here, while the path is still the plugin's, and name the
124
+ # plugin: the file lives inside an installed gem, so the fix is to report it upstream.
125
+ # It is a warning whatever the rule's severity: a stale plugin is not the user's
126
+ # mistake and must not stop the run.
127
+ def warn_about_obsolete_config(plugin, config)
128
+ messages = ConfigObsoletion.new(config).messages
129
+ return if messages.empty?
130
+
131
+ warn Rainbow(<<~WARNING).yellow
132
+ Warning: obsolete configuration found in the `#{plugin_name(plugin)}` plugin:
133
+ #{messages.join("\n")}
134
+ WARNING
135
+ end
136
+
137
+ def plugin_name(plugin)
138
+ plugin.about&.name || plugin.inspect
139
+ end
140
+
120
141
  # This is how we ensure "first-in wins": plugins can override AllCops settings that are
121
142
  # set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
122
143
  # have exclusive first-in-wins rights to that setting.
@@ -367,8 +367,8 @@ module RuboCop
367
367
  return if team.cops.empty?
368
368
 
369
369
  team.defer_corrections = @options[:diff]
370
+ team.cops.first.offenses_to_check = offenses.reject(&:corrected?)
370
371
 
371
- team.cops.first.offenses_to_check = offenses
372
372
  yield team
373
373
  end
374
374
 
@@ -51,9 +51,9 @@ module RuboCop
51
51
  Pathname(project_dir).join(lockfile_name)
52
52
  end.find(&:exist?)
53
53
  version_data = lockfile_path&.read || RuboCop::Version::STRING
54
- config_data = Pathname(
55
- args_config_file_path || ConfigFinder.find_config_path(Dir.pwd)
56
- ).read
54
+ config_path = Pathname(args_config_file_path || ConfigFinder.find_config_path(Dir.pwd))
55
+ # NOTE: A missing config file is reported by `RuboCop::CLI` with a friendly message.
56
+ config_data = config_path.exist? ? config_path.read : ''
57
57
  yaml = load_erb_templated_yaml(config_data)
58
58
 
59
59
  inherit_from_data = inherit_from_data(yaml)
@@ -181,7 +181,7 @@ module RuboCop
181
181
  yaml_code = ERB.new(content).result
182
182
 
183
183
  require 'yaml'
184
- YAML.safe_load(yaml_code, permitted_classes: [Regexp, Symbol], aliases: true)
184
+ YAML.safe_load(yaml_code, permitted_classes: [Regexp, Symbol], aliases: true) || {}
185
185
  end
186
186
  end
187
187
  end
@@ -100,15 +100,23 @@ module RuboCop
100
100
  def gemspec_filepath
101
101
  return @gemspec_filepath if defined?(@gemspec_filepath)
102
102
 
103
- @gemspec_filepath =
104
- @config.traverse_directories_upwards(@config.base_dir_for_path_parameters) do |dir|
105
- # NOTE: Can't use `dir.glob` because of JRuby 9.4.8.0 incompatibility:
106
- # https://github.com/jruby/jruby/issues/8358
107
- candidates = Pathname.glob("#{dir}/*.gemspec")
108
- # Bundler will use a gemspec whatever the filename is, as long as its the only one in
109
- # the folder.
110
- break candidates.first if candidates.one?
111
- end
103
+ @gemspec_filepath = @config.traverse_directories_upwards(
104
+ @config.base_dir_for_path_parameters, ConfigFinder.project_root
105
+ ) do |dir|
106
+ candidates = gemspec_candidates(dir)
107
+
108
+ # Bundler will use a gemspec whatever the filename is, as long as its the only one in
109
+ # the folder.
110
+ break candidates.first if candidates.one?
111
+ end
112
+ end
113
+
114
+ def gemspec_candidates(dir)
115
+ # NOTE: Can't use `dir.glob` because of JRuby 9.4.8.0 incompatibility:
116
+ # https://github.com/jruby/jruby/issues/8358
117
+ Pathname.glob("#{dir}/*.gemspec")
118
+ rescue SystemCallError
119
+ []
112
120
  end
113
121
 
114
122
  def version_from_gemspec_file(file)
@@ -179,6 +187,8 @@ module RuboCop
179
187
  return unless file && File.file?(file)
180
188
 
181
189
  File.read(file).match(pattern) { |md| md[:version].to_f }
190
+ rescue SystemCallError
191
+ nil
182
192
  end
183
193
 
184
194
  def version_file
@@ -250,6 +260,8 @@ module RuboCop
250
260
  result = line.match(/^\s*ruby\s+(\d+\.\d+)[p.\d]*\s*$/)
251
261
  return result.captures.first.to_f if result
252
262
  end
263
+ rescue SystemCallError
264
+ nil
253
265
  end
254
266
 
255
267
  def bundler_lock_file_path
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.92.0'
6
+ STRING = '1.92.2'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.92.0
4
+ version: 1.92.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -1157,7 +1157,7 @@ licenses:
1157
1157
  - MIT
1158
1158
  metadata:
1159
1159
  homepage_uri: https://rubocop.org/
1160
- changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.92.0
1160
+ changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.92.2
1161
1161
  source_code_uri: https://github.com/rubocop/rubocop/
1162
1162
  documentation_uri: https://docs.rubocop.org/rubocop/1.92/
1163
1163
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues