rubocop 1.69.2 → 1.70.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +19 -2
  5. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  6. data/lib/rubocop/config.rb +13 -4
  7. data/lib/rubocop/config_loader.rb +4 -0
  8. data/lib/rubocop/config_loader_resolver.rb +14 -3
  9. data/lib/rubocop/config_validator.rb +18 -8
  10. data/lib/rubocop/cop/base.rb +6 -0
  11. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  12. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  13. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  14. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  15. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -7
  16. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  17. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  18. data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
  19. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  20. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -6
  21. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  22. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
  23. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  24. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  25. data/lib/rubocop/cop/layout/line_length.rb +1 -0
  26. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +24 -0
  27. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  28. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  29. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  30. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  31. data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
  32. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  33. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +11 -3
  34. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  35. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  36. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +6 -14
  37. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  38. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  39. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  40. data/lib/rubocop/cop/lint/void.rb +3 -2
  41. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  42. data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
  43. data/lib/rubocop/cop/mixin/comments_help.rb +2 -0
  44. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  45. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +26 -16
  46. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  47. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  48. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  49. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  50. data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
  51. data/lib/rubocop/cop/style/and_or.rb +1 -1
  52. data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
  53. data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
  54. data/lib/rubocop/cop/style/each_for_simple_loop.rb +3 -6
  55. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  56. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  57. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  58. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -9
  59. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  60. data/lib/rubocop/cop/style/float_division.rb +8 -4
  61. data/lib/rubocop/cop/style/hash_except.rb +54 -67
  62. data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
  63. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  64. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
  65. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  66. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  67. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  68. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  69. data/lib/rubocop/cop/style/object_then.rb +13 -15
  70. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  71. data/lib/rubocop/cop/style/raise_args.rb +5 -3
  72. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  73. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  74. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  75. data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -3
  76. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -4
  77. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  78. data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
  79. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  80. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  81. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  82. data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
  83. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  84. data/lib/rubocop/cop/style/super_arguments.rb +63 -15
  85. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  86. data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
  87. data/lib/rubocop/cop/util.rb +9 -2
  88. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  89. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  90. data/lib/rubocop/lsp/logger.rb +2 -2
  91. data/lib/rubocop/lsp/routes.rb +7 -23
  92. data/lib/rubocop/lsp/runtime.rb +15 -49
  93. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  94. data/lib/rubocop/path_util.rb +11 -8
  95. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  96. data/lib/rubocop/runner.rb +5 -6
  97. data/lib/rubocop/target_ruby.rb +15 -0
  98. data/lib/rubocop/version.rb +1 -1
  99. data/lib/rubocop.rb +3 -0
  100. data/lib/ruby_lsp/rubocop/addon.rb +78 -0
  101. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
  102. metadata +12 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45af4a986637b8c3dacb16d942870c2138501ae834e79c0875b81bbf09644b54
4
- data.tar.gz: 65961fc4cb25730ad9528201e22a82427def59f6ad5f048cd01a0ca89a437c3c
3
+ metadata.gz: 55382302106a1f2c44166213aaa0c23bfccc3c0ebac5b1af95fa9073ddf59aa0
4
+ data.tar.gz: bb1a6e491c7750b3f4aff90fbe2590f289d5f85ca9bbc2d71e01bd35d420b38c
5
5
  SHA512:
6
- metadata.gz: aa6eb7a2cbf39d99cbda0faff3dfe690a61e9665847c21669bc9a005f9ac316e9404a8babc8cadf7f033bf82afcf317c8c503ede2306e8b3a8c211abaa878cb9
7
- data.tar.gz: 126f20d27ebf2e0098d0a1039230fea4178d2a196693db8c75326a7f3fdc797b1f030af3d116f2d74f69bb70cc033372ede6836962b2c47632a9ecf4f524dd56
6
+ metadata.gz: 6cff98184e513e6a57e5a82234f57a8130ef2e242eb3df675b677cfe5be8920d3cb732ce1f615385641731c328253fb65829922d371621d5e5148601f309ee51
7
+ data.tar.gz: 3c3d8e5fc22db6f9b1a1ca6f9e31a8a29467c4df358e12da099fcc528884832d00bc18842d846ee76300791c1cb76122a22b6eb079b5a713c6f7b827fbea71dc
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-24 Bozhidar Batsov
1
+ Copyright (c) 2012-25 Bozhidar Batsov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
52
52
  in your `Gemfile`:
53
53
 
54
54
  ```rb
55
- gem 'rubocop', '~> 1.69', require: false
55
+ gem 'rubocop', '~> 1.70', require: false
56
56
  ```
57
57
 
58
58
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -247,5 +247,5 @@ RuboCop's changelog is available [here](CHANGELOG.md).
247
247
 
248
248
  ## Copyright
249
249
 
250
- Copyright (c) 2012-2024 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
250
+ Copyright (c) 2012-2025 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
251
251
  further details.
data/config/default.yml CHANGED
@@ -1665,6 +1665,11 @@ Lint/ConstantOverwrittenInRescue:
1665
1665
  Enabled: pending
1666
1666
  VersionAdded: '1.31'
1667
1667
 
1668
+ Lint/ConstantReassignment:
1669
+ Description: 'Checks for constant reassignments.'
1670
+ Enabled: pending
1671
+ VersionAdded: '1.70'
1672
+
1668
1673
  Lint/ConstantResolution:
1669
1674
  Description: 'Check that constants are fully qualified with `::`.'
1670
1675
  Enabled: false
@@ -2402,6 +2407,12 @@ Lint/ShadowingOuterLocalVariable:
2402
2407
  Enabled: true
2403
2408
  VersionAdded: '0.9'
2404
2409
 
2410
+ Lint/SharedMutableDefault:
2411
+ Description: 'Checks for mutable literals used as default arguments during Hash initialization.'
2412
+ StyleGuide: '#no-mutable-defaults'
2413
+ Enabled: pending
2414
+ VersionAdded: '1.70'
2415
+
2405
2416
  Lint/StructNewOverride:
2406
2417
  Description: 'Disallow overriding the `Struct` built-in methods via `Struct.new`.'
2407
2418
  Enabled: true
@@ -3136,13 +3147,14 @@ Style/AccessModifierDeclarations:
3136
3147
  Description: 'Checks style of how access modifiers are used.'
3137
3148
  Enabled: true
3138
3149
  VersionAdded: '0.57'
3139
- VersionChanged: '0.81'
3150
+ VersionChanged: '1.70'
3140
3151
  EnforcedStyle: group
3141
3152
  SupportedStyles:
3142
3153
  - inline
3143
3154
  - group
3144
3155
  AllowModifiersOnSymbols: true
3145
3156
  AllowModifiersOnAttrs: true
3157
+ AllowModifiersOnAliasMethod: true
3146
3158
  SafeAutoCorrect: false
3147
3159
 
3148
3160
  Style/AccessorGrouping:
@@ -4316,6 +4328,11 @@ Style/IpAddresses:
4316
4328
  - '**/gems.rb'
4317
4329
  - '**/*.gemspec'
4318
4330
 
4331
+ Style/ItAssignment:
4332
+ Description: 'Checks for assignment to `it` inside a block.'
4333
+ Enabled: pending
4334
+ VersionAdded: '1.70'
4335
+
4319
4336
  Style/KeywordArgumentsMerging:
4320
4337
  Description: >-
4321
4338
  When passing an existing hash as keyword arguments, provide additional arguments
@@ -5059,7 +5076,7 @@ Style/RedundantConstantBase:
5059
5076
  VersionAdded: '1.40'
5060
5077
 
5061
5078
  Style/RedundantCurrentDirectoryInPath:
5062
- Description: 'Checks for uses a redundant current directory in path.'
5079
+ Description: 'Checks for a redundant current directory in a path given to `require_relative`.'
5063
5080
  Enabled: pending
5064
5081
  VersionAdded: '1.53'
5065
5082
 
@@ -71,11 +71,11 @@ module RuboCop
71
71
 
72
72
  warn Rainbow("\n#{pluralize(errors.size, 'error')} occurred:").red
73
73
 
74
- errors.each { |error| warn error }
74
+ errors.each { |error| warn Rainbow(error).red }
75
75
 
76
- warn <<~WARNING
76
+ warn Rainbow(<<~WARNING.strip).yellow
77
77
  Errors are usually caused by RuboCop bugs.
78
- Please, report your problems to RuboCop's issue tracker.
78
+ Please, update to the latest RuboCop version if not already in use, and report a bug if the issue still occurs on this version.
79
79
  #{bug_tracker_uri}
80
80
  Mention the following information in the issue report:
81
81
  #{RuboCop::Version.verbose}
@@ -16,6 +16,7 @@ module RuboCop
16
16
 
17
17
  CopConfig = Struct.new(:name, :metadata)
18
18
 
19
+ EMPTY_CONFIG = {}.freeze
19
20
  DEFAULT_RAILS_VERSION = 5.0
20
21
  attr_reader :loaded_path
21
22
 
@@ -80,10 +81,7 @@ module RuboCop
80
81
 
81
82
  def make_excludes_absolute
82
83
  each_key do |key|
83
- @validator.validate_section_presence(key)
84
- next unless self[key]['Exclude']
85
-
86
- self[key]['Exclude'].map! do |exclude_elem|
84
+ dig(key, 'Exclude')&.map! do |exclude_elem|
87
85
  if exclude_elem.is_a?(String) && !absolute?(exclude_elem)
88
86
  File.expand_path(File.join(base_dir_for_path_parameters, exclude_elem))
89
87
  else
@@ -123,6 +121,13 @@ module RuboCop
123
121
  @for_cop[cop]
124
122
  end
125
123
 
124
+ # @return [Config, Hash] for the given cop / cop name.
125
+ # If the given cop is enabled, returns its configuration hash.
126
+ # Otherwise, returns an empty hash.
127
+ def for_enabled_cop(cop)
128
+ cop_enabled?(cop) ? for_cop(cop) : EMPTY_CONFIG
129
+ end
130
+
126
131
  # @return [Config] for the given cop merged with that of its department (if any)
127
132
  # Note: the 'Enabled' attribute is same as that returned by `for_cop`
128
133
  def for_badge(badge)
@@ -159,6 +164,10 @@ module RuboCop
159
164
  @for_all_cops ||= self['AllCops'] || {}
160
165
  end
161
166
 
167
+ def cop_enabled?(name)
168
+ !!for_cop(name)['Enabled']
169
+ end
170
+
162
171
  def disabled_new_cops?
163
172
  for_all_cops['NewCops'] == 'disable'
164
173
  end
@@ -41,6 +41,10 @@ module RuboCop
41
41
  def clear_options
42
42
  @debug = nil
43
43
  @loaded_features = Set.new
44
+ @disable_pending_cops = nil
45
+ @enable_pending_cops = nil
46
+ @ignore_parent_exclusion = nil
47
+ @ignore_unrecognized_cops = nil
44
48
  FileFinder.root_level = nil
45
49
  end
46
50
 
@@ -163,14 +163,21 @@ module RuboCop
163
163
  end
164
164
 
165
165
  def warn_on_duplicate_setting(base_hash, derived_hash, key, **opts)
166
+ # If the file being considered is remote, don't bother checking for duplicates
167
+ return if remote_config?(opts[:file])
168
+
166
169
  return unless duplicate_setting?(base_hash, derived_hash, key, opts[:inherited_file])
167
170
 
168
171
  inherit_mode = opts[:inherit_mode]['merge'] || opts[:inherit_mode]['override']
169
172
  return if base_hash[key].is_a?(Array) && inherit_mode&.include?(key)
170
173
 
171
- puts "#{PathUtil.smart_path(opts[:file])}: " \
172
- "#{opts[:cop_name]}:#{key} overrides " \
173
- "the same parameter in #{opts[:inherited_file]}"
174
+ puts duplicate_setting_warning(opts, key)
175
+ end
176
+
177
+ def duplicate_setting_warning(opts, key)
178
+ "#{PathUtil.smart_path(opts[:file])}: " \
179
+ "#{opts[:cop_name]}:#{key} overrides " \
180
+ "the same parameter in #{opts[:inherited_file]}"
174
181
  end
175
182
 
176
183
  def determine_inherit_mode(hash, key)
@@ -242,6 +249,10 @@ module RuboCop
242
249
  uri.start_with?('http://', 'https://')
243
250
  end
244
251
 
252
+ def remote_config?(file)
253
+ file.is_a?(RemoteConfig)
254
+ end
255
+
245
256
  def handle_disabled_by_default(config, new_default_configuration)
246
257
  department_config = config.to_hash.reject { |cop| cop.include?('/') }
247
258
  department_config.each do |dept, dept_params|
@@ -3,6 +3,7 @@
3
3
  module RuboCop
4
4
  # Handles validation of configuration, for example cop names, parameter
5
5
  # names, and Ruby versions.
6
+ # rubocop:disable Metrics/ClassLength
6
7
  class ConfigValidator
7
8
  extend SimpleForwardable
8
9
 
@@ -41,8 +42,9 @@ module RuboCop
41
42
  ConfigLoader.default_configuration.key?(key)
42
43
  end
43
44
 
44
- check_obsoletions
45
+ validate_parameter_shape(valid_cop_names)
45
46
 
47
+ check_obsoletions
46
48
  alert_about_unrecognized_cops(invalid_cop_names)
47
49
  validate_new_cops_parameter
48
50
  validate_parameter_names(valid_cop_names)
@@ -64,12 +66,6 @@ module RuboCop
64
66
  target_ruby.version
65
67
  end
66
68
 
67
- def validate_section_presence(name)
68
- return unless @config.key?(name) && @config[name].nil?
69
-
70
- raise ValidationError, "empty section #{name} found in #{smart_loaded_path}"
71
- end
72
-
73
69
  private
74
70
 
75
71
  attr_reader :target_ruby
@@ -177,9 +173,22 @@ module RuboCop
177
173
  raise ValidationError, message
178
174
  end
179
175
 
176
+ def validate_parameter_shape(valid_cop_names)
177
+ valid_cop_names.each do |name|
178
+ if @config[name].nil?
179
+ raise ValidationError, "empty section #{name.inspect} found in #{smart_loaded_path}"
180
+ elsif !@config[name].is_a?(Hash)
181
+ raise ValidationError, <<~MESSAGE
182
+ The configuration for #{name.inspect} in #{smart_loaded_path} is not a Hash.
183
+
184
+ Found: #{@config[name].inspect}
185
+ MESSAGE
186
+ end
187
+ end
188
+ end
189
+
180
190
  def validate_parameter_names(valid_cop_names)
181
191
  valid_cop_names.each do |name|
182
- validate_section_presence(name)
183
192
  each_invalid_parameter(name) do |param, supported_params|
184
193
  warn Rainbow(<<~MESSAGE).yellow
185
194
  Warning: #{name} does not support #{param} parameter.
@@ -277,4 +286,5 @@ module RuboCop
277
286
  "is supposed to be #{supposed_values} and #{Rainbow(value).yellow} is not."
278
287
  end
279
288
  end
289
+ # rubocop:enable Metrics/ClassLength
280
290
  end
@@ -261,6 +261,12 @@ module RuboCop
261
261
  @config.target_ruby_version
262
262
  end
263
263
 
264
+ # Returns a gems locked versions (i.e. from Gemfile.lock or gems.locked)
265
+ # @returns [Gem::Version | nil] The locked gem version, or nil if the gem is not present.
266
+ def target_gem_version(gem_name)
267
+ @config.gem_versions_in_target && @config.gem_versions_in_target[gem_name]
268
+ end
269
+
264
270
  def parser_engine
265
271
  @config.parser_engine
266
272
  end
@@ -161,7 +161,7 @@ module RuboCop
161
161
  end
162
162
 
163
163
  def gem_options(node)
164
- return [] unless node.last_argument&.type == :hash
164
+ return [] unless node.last_argument&.hash_type?
165
165
 
166
166
  node.last_argument.keys.map(&:value)
167
167
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Use `config.cop_enabled?('Department/CopName')` instead of
7
+ # traversing the config hash.
8
+ #
9
+ # @example
10
+ # # `for_cop(...)['Enabled']
11
+ #
12
+ # # bad
13
+ # config.for_cop('Department/CopName')['Enabled']
14
+ #
15
+ # # good
16
+ # config.cop_enabled?('Department/CopName')
17
+ #
18
+ # @example
19
+ # # when keeping a cop's config in a local and then checking the `Enabled` key
20
+ #
21
+ # # bad
22
+ # cop_config = config.for_cop('Department/CopName')
23
+ # cop_config['Enabled'] && cop_config['Foo']
24
+ #
25
+ # # good
26
+ # config.for_enabled_cop('Department/CopName')['Foo']
27
+ #
28
+ class CopEnabled < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Use `%<replacement>s` instead of `%<source>s`.'
32
+ MSG_HASH = 'Consider replacing uses of `%<hash_name>s` with `config.for_enabled_cop`.'
33
+
34
+ RESTRICT_ON_SEND = [:[]].freeze
35
+
36
+ # @!method for_cop_enabled?(node)
37
+ def_node_matcher :for_cop_enabled?, <<~PATTERN
38
+ (send
39
+ (send
40
+ ${(send nil? :config) (ivar :@config)} :for_cop
41
+ $(str _)) :[]
42
+ (str "Enabled"))
43
+ PATTERN
44
+
45
+ # @!method config_enabled_lookup?(node)
46
+ def_node_matcher :config_enabled_lookup?, <<~PATTERN
47
+ (send
48
+ {(lvar $_) (ivar $_) (send nil? $_)} :[]
49
+ (str "Enabled"))
50
+ PATTERN
51
+
52
+ def on_send(node)
53
+ if (config_var, cop_name = for_cop_enabled?(node))
54
+ handle_for_cop(node, config_var, cop_name)
55
+ elsif (config_var = config_enabled_lookup?(node))
56
+ return unless config_var.end_with?('_config')
57
+
58
+ handle_hash(node, config_var)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def handle_for_cop(node, config_var, cop_name)
65
+ source = node.source
66
+ quote = cop_name.loc.begin.source
67
+ cop_name = cop_name.value
68
+
69
+ replacement = "#{config_var.source}.cop_enabled?(#{quote}#{cop_name}#{quote})"
70
+ message = format(MSG, source: source, replacement: replacement)
71
+
72
+ add_offense(node, message: message) do |corrector|
73
+ corrector.replace(node, replacement)
74
+ end
75
+ end
76
+
77
+ def handle_hash(node, config_var)
78
+ message = format(MSG_HASH, hash_name: config_var)
79
+
80
+ add_offense(node, message: message)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -21,16 +21,17 @@ module RuboCop
21
21
 
22
22
  # @!method node_type_check(node)
23
23
  def_node_matcher :node_type_check, <<~PATTERN
24
- (send (send $_ :type) :== (sym $_))
24
+ (send (call _ :type) :== (sym $_))
25
25
  PATTERN
26
26
 
27
27
  def on_send(node)
28
- node_type_check(node) do |receiver, node_type|
28
+ node_type_check(node) do |node_type|
29
29
  return unless Parser::Meta::NODE_TYPES.include?(node_type)
30
30
 
31
31
  message = format(MSG, type: node_type)
32
32
  add_offense(node, message: message) do |corrector|
33
- range = node.source_range.with(begin_pos: receiver.source_range.end_pos + 1)
33
+ range = node.receiver.loc.selector.join(node.source_range.end)
34
+
34
35
  corrector.replace(range, "#{node_type}_type?")
35
36
  end
36
37
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'internal_affairs/cop_description'
4
+ require_relative 'internal_affairs/cop_enabled'
4
5
  require_relative 'internal_affairs/create_empty_file'
5
6
  require_relative 'internal_affairs/empty_line_between_expect_offense_and_correction'
6
7
  require_relative 'internal_affairs/example_description'
@@ -141,16 +141,10 @@ module RuboCop
141
141
  end
142
142
 
143
143
  def enforce_hash_argument_with_separator?
144
- return false unless hash_argument_config['Enabled']
145
-
146
144
  RuboCop::Cop::Layout::HashAlignment::SEPARATOR_ALIGNMENT_STYLES.any? do |style|
147
- hash_argument_config[style]&.include?('separator')
145
+ config.for_enabled_cop('Layout/HashAlignment')[style]&.include?('separator')
148
146
  end
149
147
  end
150
-
151
- def hash_argument_config
152
- config.for_cop('Layout/HashAlignment')
153
- end
154
148
  end
155
149
  end
156
150
  end
@@ -86,6 +86,7 @@ module RuboCop
86
86
 
87
87
  def on_send(node)
88
88
  return unless node.bare_access_modifier? && !node.block_literal?
89
+ return if same_line?(node, node.right_sibling)
89
90
  return if expected_empty_lines?(node)
90
91
 
91
92
  message = message(node)
@@ -70,7 +70,7 @@ module RuboCop
70
70
  end
71
71
 
72
72
  def check_assignment(token)
73
- return unless aligned_with_preceding_assignment(token) == :no
73
+ return unless aligned_with_preceding_equals_operator(token) == :no
74
74
 
75
75
  message = format(MSG_UNALIGNED_ASGN, location: 'preceding')
76
76
  add_offense(token.pos, message: message) do |corrector|
@@ -269,17 +269,12 @@ module RuboCop
269
269
  end
270
270
 
271
271
  def enforce_first_argument_with_fixed_indentation?
272
- return false unless argument_alignment_config['Enabled']
273
-
272
+ argument_alignment_config = config.for_enabled_cop('Layout/ArgumentAlignment')
274
273
  argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
275
274
  end
276
275
 
277
276
  def enable_layout_first_method_argument_line_break?
278
- config.for_cop('Layout/FirstMethodArgumentLineBreak')['Enabled']
279
- end
280
-
281
- def argument_alignment_config
282
- config.for_cop('Layout/ArgumentAlignment')
277
+ config.cop_enabled?('Layout/FirstMethodArgumentLineBreak')
283
278
  end
284
279
  end
285
280
  end
@@ -180,13 +180,8 @@ module RuboCop
180
180
  end
181
181
 
182
182
  def enforce_first_argument_with_fixed_indentation?
183
- return false unless array_alignment_config['Enabled']
184
-
185
- array_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
186
- end
187
-
188
- def array_alignment_config
189
- config.for_cop('Layout/ArrayAlignment')
183
+ argument_alignment_config = config.for_enabled_cop('Layout/ArrayAlignment')
184
+ argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
190
185
  end
191
186
  end
192
187
  end
@@ -225,14 +225,9 @@ module RuboCop
225
225
  end
226
226
 
227
227
  def enforce_first_argument_with_fixed_indentation?
228
- return false unless argument_alignment_config['Enabled']
229
-
228
+ argument_alignment_config = config.for_enabled_cop('Layout/ArgumentAlignment')
230
229
  argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
231
230
  end
232
-
233
- def argument_alignment_config
234
- config.for_cop('Layout/ArgumentAlignment')
235
- end
236
231
  end
237
232
  end
238
233
  end
@@ -202,6 +202,7 @@ module RuboCop
202
202
 
203
203
  ignore_node(last_argument)
204
204
  end
205
+ alias on_csend on_send
205
206
  alias on_super on_send
206
207
  alias on_yield on_send
207
208
 
@@ -227,6 +228,7 @@ module RuboCop
227
228
  left_sibling = argument_before_hash(node)
228
229
  parent_loc = node.parent.loc
229
230
  selector = left_sibling || parent_loc.selector || parent_loc.expression
231
+
230
232
  same_line?(selector, node.pairs.first)
231
233
  end
232
234
 
@@ -382,13 +384,13 @@ module RuboCop
382
384
  end
383
385
 
384
386
  def enforce_first_argument_with_fixed_indentation?
385
- return false unless argument_alignment_config['Enabled']
386
-
387
+ argument_alignment_config = config.for_enabled_cop('Layout/ArgumentAlignment')
387
388
  argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
388
389
  end
389
390
 
390
- def argument_alignment_config
391
- config.for_cop('Layout/ArgumentAlignment')
391
+ def same_line?(node1, node2)
392
+ # Override `Util#same_line?`
393
+ super || node1.last_line == line(node2)
392
394
  end
393
395
  end
394
396
  end
@@ -75,6 +75,7 @@ module RuboCop
75
75
  autocorrect(corrector, outermost_send)
76
76
  end
77
77
  end
78
+ alias on_csend on_send
78
79
 
79
80
  private
80
81
 
@@ -101,7 +101,7 @@ module RuboCop
101
101
  ranges << loc.expression
102
102
  elsif literal.heredoc?
103
103
  ranges << loc.heredoc_body
104
- elsif loc.respond_to?(:begin) && loc.begin
104
+ elsif (loc.respond_to?(:begin) && loc.begin) || ignored_parent?(literal)
105
105
  ranges << loc.expression
106
106
  end
107
107
  end
@@ -127,6 +127,12 @@ module RuboCop
127
127
  comment_ranges(processed_source.comments)
128
128
  end
129
129
 
130
+ def ignored_parent?(node)
131
+ return false unless node.parent
132
+
133
+ node.parent.type?(:regexp, :xstr)
134
+ end
135
+
130
136
  def no_space_style?
131
137
  cop_config['EnforcedStyle'] == 'no_space'
132
138
  end
@@ -127,7 +127,7 @@ module RuboCop
127
127
 
128
128
  def base_column(child)
129
129
  grandparent = child.parent.parent
130
- if grandparent&.type == :pair
130
+ if grandparent&.pair_type?
131
131
  grandparent.loc.column
132
132
  else
133
133
  child.source_range.source_line =~ /\S/
@@ -90,6 +90,7 @@ module RuboCop
90
90
  alias on_array on_potential_breakable_node
91
91
  alias on_hash on_potential_breakable_node
92
92
  alias on_send on_potential_breakable_node
93
+ alias on_csend on_potential_breakable_node
93
94
  alias on_def on_potential_breakable_node
94
95
 
95
96
  def on_new_investigation
@@ -33,6 +33,18 @@ module RuboCop
33
33
  #
34
34
  # @example AllowMultilineFinalElement: false (default)
35
35
  #
36
+ # # bad
37
+ # foo(a, b,
38
+ # c
39
+ # )
40
+ #
41
+ # # bad
42
+ # foo(
43
+ # a, b, {
44
+ # foo: "bar",
45
+ # }
46
+ # )
47
+ #
36
48
  # # good
37
49
  # foo(
38
50
  # a,
@@ -44,6 +56,18 @@ module RuboCop
44
56
  #
45
57
  # @example AllowMultilineFinalElement: true
46
58
  #
59
+ # # bad
60
+ # foo(a, b,
61
+ # c
62
+ # )
63
+ #
64
+ # # good
65
+ # foo(
66
+ # a, b, {
67
+ # foo: "bar",
68
+ # }
69
+ # )
70
+ #
47
71
  # # good
48
72
  # foo(
49
73
  # a,
@@ -115,7 +115,7 @@ module RuboCop
115
115
  end
116
116
 
117
117
  def single_line_block_chain_enabled?
118
- @config.for_cop('Layout/SingleLineBlockChain')['Enabled']
118
+ @config.cop_enabled?('Layout/SingleLineBlockChain')
119
119
  end
120
120
 
121
121
  def convertible_block?(node)
@@ -22,7 +22,7 @@ module RuboCop
22
22
 
23
23
  def on_def(node)
24
24
  args = node.arguments
25
- return unless args.loc.begin&.is?('(')
25
+ return unless args.parenthesized_call?
26
26
 
27
27
  expr = args.source_range
28
28
  pos_before_left_paren = range_between(expr.begin_pos - 1, expr.begin_pos)
@@ -242,12 +242,12 @@ module RuboCop
242
242
  return !aligned_with_operator?(operator) unless type == :assignment
243
243
 
244
244
  token = Token.new(operator, nil, operator.source)
245
- align_preceding = aligned_with_preceding_assignment(token)
245
+ align_preceding = aligned_with_preceding_equals_operator(token)
246
246
 
247
247
  return false if align_preceding == :yes ||
248
- aligned_with_subsequent_assignment(token) == :none
248
+ aligned_with_subsequent_equals_operator(token) == :none
249
249
 
250
- aligned_with_subsequent_assignment(token) != :yes
250
+ aligned_with_subsequent_equals_operator(token) != :yes
251
251
  end
252
252
 
253
253
  def excess_trailing_space?(right_operand, with_space)