rubocop 0.73.0 → 0.74.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/console +1 -0
  4. data/config/default.yml +2 -1
  5. data/lib/rubocop.rb +3 -0
  6. data/lib/rubocop/ast/node.rb +1 -7
  7. data/lib/rubocop/config.rb +17 -537
  8. data/lib/rubocop/config_obsoletion.rb +201 -0
  9. data/lib/rubocop/config_validator.rb +239 -0
  10. data/lib/rubocop/cop/layout/extra_spacing.rb +14 -53
  11. data/lib/rubocop/cop/layout/indentation_width.rb +19 -5
  12. data/lib/rubocop/cop/layout/space_around_operators.rb +42 -23
  13. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +22 -40
  14. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  15. data/lib/rubocop/cop/lint/empty_interpolation.rb +4 -4
  16. data/lib/rubocop/cop/lint/erb_new_arguments.rb +56 -0
  17. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +7 -8
  18. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +6 -6
  19. data/lib/rubocop/cop/lint/unneeded_splat_expansion.rb +6 -1
  20. data/lib/rubocop/cop/metrics/line_length.rb +6 -0
  21. data/lib/rubocop/cop/mixin/documentation_comment.rb +0 -2
  22. data/lib/rubocop/cop/mixin/interpolation.rb +27 -0
  23. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +87 -0
  24. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -5
  25. data/lib/rubocop/cop/style/commented_keyword.rb +8 -28
  26. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -3
  27. data/lib/rubocop/cop/style/constant_visibility.rb +13 -2
  28. data/lib/rubocop/cop/style/guard_clause.rb +39 -10
  29. data/lib/rubocop/cop/style/lambda.rb +0 -2
  30. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +4 -6
  31. data/lib/rubocop/cop/style/variable_interpolation.rb +6 -16
  32. data/lib/rubocop/path_util.rb +1 -1
  33. data/lib/rubocop/processed_source.rb +4 -0
  34. data/lib/rubocop/rspec/expect_offense.rb +4 -1
  35. data/lib/rubocop/version.rb +1 -1
  36. metadata +5 -2
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # This class handles obsolete configuration.
5
+ class ConfigObsoletion
6
+ RENAMED_COPS = {
7
+ 'Style/SingleSpaceBeforeFirstArg' => 'Layout/SpaceBeforeFirstArg',
8
+ 'Style/MethodCallParentheses' => 'Style/MethodCallWithoutArgsParentheses',
9
+ 'Style/DeprecatedHashMethods' => 'Style/PreferredHashMethods',
10
+ 'Style/OpMethod' => 'Naming/BinaryOperatorParameterName',
11
+ 'Layout/FirstParameterIndentation' => 'Layout/IndentFirstArgument',
12
+ 'Layout/IndentArray' => 'Layout/IndentFirstArrayElement',
13
+ 'Layout/IndentHash' => 'Layout/IndentFirstHashElement'
14
+ }.map do |old_name, new_name|
15
+ [old_name, "The `#{old_name}` cop has been renamed to `#{new_name}`."]
16
+ end
17
+
18
+ MOVED_COPS = {
19
+ 'Security' => 'Lint/Eval',
20
+ 'Naming' => %w[Style/ClassAndModuleCamelCase Style/ConstantName
21
+ Style/FileName Style/MethodName Style/PredicateName
22
+ Style/VariableName Style/VariableNumber
23
+ Style/AccessorMethodName Style/AsciiIdentifiers],
24
+ 'Layout' => %w[Lint/BlockAlignment Lint/EndAlignment
25
+ Lint/DefEndAlignment],
26
+ 'Lint' => 'Style/FlipFlop'
27
+ }.map do |new_department, old_names|
28
+ Array(old_names).map do |old_name|
29
+ [old_name, "The `#{old_name}` cop has been moved to " \
30
+ "`#{new_department}/#{old_name.split('/').last}`."]
31
+ end
32
+ end
33
+
34
+ REMOVED_COPS = {
35
+ 'Rails/DefaultScope' => nil,
36
+ 'Layout/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
37
+ 'Layout/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
38
+ 'Style/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
39
+ 'Style/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
40
+ 'Style/TrailingComma' => 'Style/TrailingCommaInArguments, ' \
41
+ 'Style/TrailingCommaInArrayLiteral, and/or ' \
42
+ 'Style/TrailingCommaInHashLiteral',
43
+ 'Style/TrailingCommaInLiteral' => 'Style/TrailingCommaInArrayLiteral ' \
44
+ 'and/or ' \
45
+ 'Style/TrailingCommaInHashLiteral',
46
+ 'Lint/RescueWithoutErrorClass' => 'Style/RescueStandardError'
47
+ }.map do |old_name, other_cops|
48
+ if other_cops
49
+ more = ". Please use #{other_cops} instead".gsub(%r{[A-Z]\w+/\w+},
50
+ '`\&`')
51
+ end
52
+ [old_name, "The `#{old_name}` cop has been removed#{more}."]
53
+ end
54
+
55
+ REMOVED_COPS_WITH_REASON = {
56
+ 'Lint/InvalidCharacterLiteral' => 'it was never being actually triggered',
57
+ 'Lint/SpaceBeforeFirstArg' =>
58
+ 'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \
59
+ '`Layout/SpaceBeforeFirstArg` instead'
60
+ }.map do |cop_name, reason|
61
+ [cop_name, "The `#{cop_name}` cop has been removed since #{reason}."]
62
+ end
63
+
64
+ SPLIT_COPS = {
65
+ 'Style/MethodMissing' =>
66
+ 'The `Style/MethodMissing` cop has been split into ' \
67
+ '`Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.'
68
+ }.to_a
69
+
70
+ OBSOLETE_COPS = Hash[*(RENAMED_COPS + MOVED_COPS + REMOVED_COPS +
71
+ REMOVED_COPS_WITH_REASON + SPLIT_COPS).flatten]
72
+
73
+ OBSOLETE_PARAMETERS = [
74
+ {
75
+ cops: %w[Layout/SpaceAroundOperators Style/SpaceAroundOperators],
76
+ parameters: 'MultiSpaceAllowedForOperators',
77
+ alternative: 'If your intention was to allow extra spaces for ' \
78
+ 'alignment, please use AllowForAlignment: true instead.'
79
+ },
80
+ {
81
+ cops: 'Style/Encoding',
82
+ parameters: %w[EnforcedStyle SupportedStyles
83
+ AutoCorrectEncodingComment],
84
+ alternative: 'Style/Encoding no longer supports styles. ' \
85
+ 'The "never" behavior is always assumed.'
86
+ },
87
+ {
88
+ cops: 'Style/IfUnlessModifier',
89
+ parameters: 'MaxLineLength',
90
+ alternative: '`Style/IfUnlessModifier: MaxLineLength` has been ' \
91
+ 'removed. Use `Metrics/LineLength: Max` instead'
92
+ },
93
+ {
94
+ cops: 'Style/WhileUntilModifier',
95
+ parameters: 'MaxLineLength',
96
+ alternative: '`Style/WhileUntilModifier: MaxLineLength` has been ' \
97
+ 'removed. Use `Metrics/LineLength: Max` instead'
98
+ },
99
+ {
100
+ cops: 'AllCops',
101
+ parameters: 'RunRailsCops',
102
+ alternative: "Use the following configuration instead:\n" \
103
+ "Rails:\n Enabled: true"
104
+ },
105
+ {
106
+ cops: 'Layout/CaseIndentation',
107
+ parameters: 'IndentWhenRelativeTo',
108
+ alternative: '`IndentWhenRelativeTo` has been renamed to ' \
109
+ '`EnforcedStyle`'
110
+ },
111
+ {
112
+ cops: %w[Lint/BlockAlignment Layout/BlockAlignment Lint/EndAlignment
113
+ Layout/EndAlignment Lint/DefEndAlignment
114
+ Layout/DefEndAlignment],
115
+ parameters: 'AlignWith',
116
+ alternative: '`AlignWith` has been renamed to `EnforcedStyleAlignWith`'
117
+ },
118
+ {
119
+ cops: 'Rails/UniqBeforePluck',
120
+ parameters: 'EnforcedMode',
121
+ alternative: '`EnforcedMode` has been renamed to `EnforcedStyle`'
122
+ }
123
+ ].freeze
124
+
125
+ OBSOLETE_ENFORCED_STYLES = [
126
+ {
127
+ cop: 'Layout/IndentationConsistency',
128
+ parameter: 'EnforcedStyle',
129
+ enforced_style: 'rails',
130
+ alternative: '`EnforcedStyle: rails` has been renamed to ' \
131
+ '`EnforcedStyle: indented_internal_methods`'
132
+ }
133
+ ].freeze
134
+
135
+ def initialize(config)
136
+ @config = config
137
+ end
138
+
139
+ def reject_obsolete_cops_and_parameters
140
+ messages = [obsolete_cops, obsolete_parameters,
141
+ obsolete_enforced_style].flatten.compact
142
+ return if messages.empty?
143
+
144
+ raise ValidationError, messages.join("\n")
145
+ end
146
+
147
+ private
148
+
149
+ def obsolete_cops
150
+ OBSOLETE_COPS.map do |cop_name, message|
151
+ next unless @config.key?(cop_name) ||
152
+ @config.key?(Cop::Badge.parse(cop_name).cop_name)
153
+
154
+ message + "\n(obsolete configuration found in " \
155
+ "#{smart_loaded_path}, please update it)"
156
+ end
157
+ end
158
+
159
+ def obsolete_enforced_style
160
+ OBSOLETE_ENFORCED_STYLES.map do |params|
161
+ obsolete_enforced_style_message(params[:cop], params[:parameter],
162
+ params[:enforced_style],
163
+ params[:alternative])
164
+ end
165
+ end
166
+
167
+ def obsolete_enforced_style_message(cop, param, enforced_style, alternative)
168
+ style = @config[cop]&.detect { |key, _| key.start_with?(param) }
169
+
170
+ return unless style && style[1] == enforced_style
171
+
172
+ "obsolete `#{param}: #{enforced_style}` (for #{cop}) found in " \
173
+ "#{smart_loaded_path}\n#{alternative}"
174
+ end
175
+
176
+ def obsolete_parameters
177
+ OBSOLETE_PARAMETERS.map do |params|
178
+ obsolete_parameter_message(params[:cops], params[:parameters],
179
+ params[:alternative])
180
+ end
181
+ end
182
+
183
+ def obsolete_parameter_message(cops, parameters, alternative)
184
+ Array(cops).map do |cop|
185
+ obsolete_parameters = Array(parameters).select do |param|
186
+ @config[cop]&.key?(param)
187
+ end
188
+ next if obsolete_parameters.empty?
189
+
190
+ obsolete_parameters.map do |parameter|
191
+ "obsolete parameter #{parameter} (for #{cop}) found in " \
192
+ "#{smart_loaded_path}\n#{alternative}"
193
+ end
194
+ end
195
+ end
196
+
197
+ def smart_loaded_path
198
+ PathUtil.smart_path(@config.loaded_path)
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,239 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module RuboCop
6
+ # Handles validation of configuration, for example cop names, parameter
7
+ # names, and Ruby versions.
8
+ class ConfigValidator
9
+ extend Forwardable
10
+
11
+ COMMON_PARAMS = %w[Exclude Include Severity inherit_mode
12
+ AutoCorrect StyleGuide Details].freeze
13
+ INTERNAL_PARAMS = %w[Description StyleGuide VersionAdded
14
+ VersionChanged Reference Safe SafeAutoCorrect].freeze
15
+
16
+ # 2.3 is the oldest officially supported Ruby version.
17
+ DEFAULT_RUBY_VERSION = 2.3
18
+ KNOWN_RUBIES = [2.3, 2.4, 2.5, 2.6, 2.7].freeze
19
+ OBSOLETE_RUBIES = {
20
+ 1.9 => '0.50', 2.0 => '0.50', 2.1 => '0.58', 2.2 => '0.69'
21
+ }.freeze
22
+ RUBY_VERSION_FILENAME = '.ruby-version'
23
+
24
+ def_delegators :@config,
25
+ :smart_loaded_path, :for_all_cops, :find_file_upwards,
26
+ :base_dir_for_path_parameters, :bundler_lock_file_path
27
+
28
+ def initialize(config)
29
+ @config = config
30
+ @config_obsoletion = ConfigObsoletion.new(config)
31
+ end
32
+
33
+ def validate
34
+ # Don't validate RuboCop's own files. Avoids infinite recursion.
35
+ base_config_path = File.expand_path(File.join(ConfigLoader::RUBOCOP_HOME,
36
+ 'config'))
37
+ return if File.expand_path(@config.loaded_path)
38
+ .start_with?(base_config_path)
39
+
40
+ valid_cop_names, invalid_cop_names = @config.keys.partition do |key|
41
+ ConfigLoader.default_configuration.key?(key)
42
+ end
43
+
44
+ @config_obsoletion.reject_obsolete_cops_and_parameters
45
+
46
+ warn_about_unrecognized_cops(invalid_cop_names)
47
+ check_target_ruby
48
+ validate_parameter_names(valid_cop_names)
49
+ validate_enforced_styles(valid_cop_names)
50
+ validate_syntax_cop
51
+ reject_mutually_exclusive_defaults
52
+ end
53
+
54
+ def target_ruby_version
55
+ @target_ruby_version ||= begin
56
+ if for_all_cops['TargetRubyVersion']
57
+ @target_ruby_version_source = :rubocop_yml
58
+
59
+ for_all_cops['TargetRubyVersion'].to_f
60
+ elsif target_ruby_version_from_version_file
61
+ @target_ruby_version_source = :ruby_version_file
62
+
63
+ target_ruby_version_from_version_file
64
+ elsif target_ruby_version_from_bundler_lock_file
65
+ @target_ruby_version_source = :bundler_lock_file
66
+
67
+ target_ruby_version_from_bundler_lock_file
68
+ else
69
+ DEFAULT_RUBY_VERSION
70
+ end
71
+ end
72
+ end
73
+
74
+ def validate_section_presence(name)
75
+ return unless @config.key?(name) && @config[name].nil?
76
+
77
+ raise ValidationError,
78
+ "empty section #{name} found in #{smart_loaded_path}"
79
+ end
80
+
81
+ private
82
+
83
+ def check_target_ruby
84
+ return if KNOWN_RUBIES.include?(target_ruby_version)
85
+
86
+ msg = if OBSOLETE_RUBIES.include?(target_ruby_version)
87
+ "RuboCop found unsupported Ruby version #{target_ruby_version} " \
88
+ "in #{target_ruby_source}. #{target_ruby_version}-compatible " \
89
+ 'analysis was dropped after version ' \
90
+ "#{OBSOLETE_RUBIES[target_ruby_version]}."
91
+ else
92
+ 'RuboCop found unknown Ruby version ' \
93
+ "#{target_ruby_version.inspect} in #{target_ruby_source}."
94
+ end
95
+
96
+ msg += "\nSupported versions: #{KNOWN_RUBIES.join(', ')}"
97
+
98
+ raise ValidationError, msg
99
+ end
100
+
101
+ def warn_about_unrecognized_cops(invalid_cop_names)
102
+ invalid_cop_names.each do |name|
103
+ # There could be a custom cop with this name. If so, don't warn
104
+ next if Cop::Cop.registry.contains_cop_matching?([name])
105
+
106
+ # Special case for inherit_mode, which is a directive that we keep in
107
+ # the configuration (even though it's not a cop), because it's easier
108
+ # to do so than to pass the value around to various methods.
109
+ next if name == 'inherit_mode'
110
+
111
+ warn Rainbow("Warning: unrecognized cop #{name} found in " \
112
+ "#{smart_loaded_path}").yellow
113
+ end
114
+ end
115
+
116
+ def validate_syntax_cop
117
+ syntax_config = @config['Lint/Syntax']
118
+ default_config = ConfigLoader.default_configuration['Lint/Syntax']
119
+
120
+ return unless syntax_config &&
121
+ default_config.merge(syntax_config) != default_config
122
+
123
+ raise ValidationError,
124
+ "configuration for Syntax cop found in #{smart_loaded_path}\n" \
125
+ 'It\'s not possible to disable this cop.'
126
+ end
127
+
128
+ def validate_parameter_names(valid_cop_names)
129
+ valid_cop_names.each do |name|
130
+ validate_section_presence(name)
131
+ default_config = ConfigLoader.default_configuration[name]
132
+
133
+ @config[name].each_key do |param|
134
+ next if COMMON_PARAMS.include?(param) || default_config.key?(param)
135
+
136
+ message =
137
+ "Warning: #{name} does not support #{param} parameter.\n\n" \
138
+ "Supported parameters are:\n\n" \
139
+ " - #{(default_config.keys - INTERNAL_PARAMS).join("\n - ")}\n"
140
+
141
+ warn Rainbow(message).yellow.to_s
142
+ end
143
+ end
144
+ end
145
+
146
+ def validate_enforced_styles(valid_cop_names)
147
+ valid_cop_names.each do |name|
148
+ styles = @config[name].select { |key, _| key.start_with?('Enforced') }
149
+
150
+ styles.each do |style_name, style|
151
+ supported_key = RuboCop::Cop::Util.to_supported_styles(style_name)
152
+ valid = ConfigLoader.default_configuration[name][supported_key]
153
+
154
+ next unless valid
155
+ next if valid.include?(style)
156
+ next if validate_support_and_has_list(name, style, valid)
157
+
158
+ msg = "invalid #{style_name} '#{style}' for #{name} found in " \
159
+ "#{smart_loaded_path}\n" \
160
+ "Valid choices are: #{valid.join(', ')}"
161
+ raise ValidationError, msg
162
+ end
163
+ end
164
+ end
165
+
166
+ def validate_support_and_has_list(name, formats, valid)
167
+ ConfigLoader.default_configuration[name]['AllowMultipleStyles'] &&
168
+ formats.is_a?(Array) &&
169
+ formats.all? { |format| valid.include?(format) }
170
+ end
171
+
172
+ def target_ruby_source
173
+ case @target_ruby_version_source
174
+ when :ruby_version_file
175
+ "`#{RUBY_VERSION_FILENAME}`"
176
+ when :bundler_lock_file
177
+ "`#{bundler_lock_file_path}`"
178
+ when :rubocop_yml
179
+ "`TargetRubyVersion` parameter (in #{smart_loaded_path})"
180
+ end
181
+ end
182
+
183
+ def ruby_version_file
184
+ @ruby_version_file ||=
185
+ find_file_upwards(RUBY_VERSION_FILENAME, base_dir_for_path_parameters)
186
+ end
187
+
188
+ def target_ruby_version_from_version_file
189
+ file = ruby_version_file
190
+ return unless file && File.file?(file)
191
+
192
+ @target_ruby_version_from_version_file ||=
193
+ File.read(file).match(/\A(ruby-)?(?<version>\d+\.\d+)/) do |md|
194
+ md[:version].to_f
195
+ end
196
+ end
197
+
198
+ def target_ruby_version_from_bundler_lock_file
199
+ @target_ruby_version_from_bundler_lock_file ||=
200
+ read_ruby_version_from_bundler_lock_file
201
+ end
202
+
203
+ def read_ruby_version_from_bundler_lock_file
204
+ lock_file_path = bundler_lock_file_path
205
+ return nil unless lock_file_path
206
+
207
+ in_ruby_section = false
208
+ File.foreach(lock_file_path) do |line|
209
+ # If ruby is in Gemfile.lock or gems.lock, there should be two lines
210
+ # towards the bottom of the file that look like:
211
+ # RUBY VERSION
212
+ # ruby W.X.YpZ
213
+ # We ultimately want to match the "ruby W.X.Y.pZ" line, but there's
214
+ # extra logic to make sure we only start looking once we've seen the
215
+ # "RUBY VERSION" line.
216
+ in_ruby_section ||= line.match(/^\s*RUBY\s*VERSION\s*$/)
217
+ next unless in_ruby_section
218
+
219
+ # We currently only allow this feature to work with MRI ruby. If jruby
220
+ # (or something else) is used by the project, it's lock file will have a
221
+ # line that looks like:
222
+ # RUBY VERSION
223
+ # ruby W.X.YpZ (jruby x.x.x.x)
224
+ # The regex won't match in this situation.
225
+ result = line.match(/^\s*ruby\s+(\d+\.\d+)[p.\d]*\s*$/)
226
+ return result.captures.first.to_f if result
227
+ end
228
+ end
229
+
230
+ def reject_mutually_exclusive_defaults
231
+ disabled_by_default = for_all_cops['DisabledByDefault']
232
+ enabled_by_default = for_all_cops['EnabledByDefault']
233
+ return unless disabled_by_default && enabled_by_default
234
+
235
+ msg = 'Cops cannot be both enabled by default and disabled by default'
236
+ raise ValidationError, msg
237
+ end
238
+ end
239
+ end
@@ -41,12 +41,7 @@ module RuboCop
41
41
  def investigate(processed_source)
42
42
  return if processed_source.blank?
43
43
 
44
- if force_equal_sign_alignment?
45
- @asgn_tokens = assignment_tokens
46
- @asgn_lines = @asgn_tokens.map(&:line)
47
- # Don't attempt to correct the same = more than once
48
- @corrected = Set.new
49
- end
44
+ @corrected = Set.new if force_equal_sign_alignment?
50
45
 
51
46
  processed_source.tokens.each_cons(2) do |token1, token2|
52
47
  check_tokens(processed_source.ast, token1, token2)
@@ -65,24 +60,10 @@ module RuboCop
65
60
 
66
61
  private
67
62
 
68
- def assignment_tokens
69
- tokens = processed_source.tokens.select(&:equal_sign?)
70
- # we don't want to operate on equals signs which are part of an
71
- # optarg in a method definition
72
- # e.g.: def method(optarg = default_val); end
73
- tokens = remove_optarg_equals(tokens, processed_source)
74
-
75
- # Only attempt to align the first = on each line
76
- Set.new(tokens.uniq(&:line))
77
- end
78
-
79
63
  def check_tokens(ast, token1, token2)
80
64
  return if token2.type == :tNL
81
65
 
82
- if force_equal_sign_alignment? &&
83
- @asgn_tokens.include?(token2) &&
84
- (@asgn_lines.include?(token2.line - 1) ||
85
- @asgn_lines.include?(token2.line + 1))
66
+ if force_equal_sign_alignment? && assignment_tokens.include?(token2)
86
67
  check_assignment(token2)
87
68
  else
88
69
  check_other(token1, token2, ast)
@@ -90,24 +71,12 @@ module RuboCop
90
71
  end
91
72
 
92
73
  def check_assignment(token)
93
- assignment_line = ''
94
- message = ''
95
- if should_aligned_with_preceding_line?(token)
96
- assignment_line = processed_source.preceding_line(token)
97
- message = format(MSG_UNALIGNED_ASGN, location: 'preceding')
98
- else
99
- assignment_line = processed_source.following_line(token)
100
- message = format(MSG_UNALIGNED_ASGN, location: 'following')
101
- end
102
- return if aligned_assignment?(token.pos, assignment_line)
74
+ return unless aligned_with_preceding_assignment(token) == :no
103
75
 
76
+ message = format(MSG_UNALIGNED_ASGN, location: 'preceding')
104
77
  add_offense(token.pos, location: token.pos, message: message)
105
78
  end
106
79
 
107
- def should_aligned_with_preceding_line?(token)
108
- @asgn_lines.include?(token.line - 1)
109
- end
110
-
111
80
  def check_other(token1, token2, ast)
112
81
  return false if allow_for_trailing_comments? &&
113
82
  token2.text.start_with?('#')
@@ -188,8 +157,8 @@ module RuboCop
188
157
  end
189
158
 
190
159
  def align_equal_signs(range, corrector)
191
- lines = contiguous_assignment_lines(range)
192
- tokens = @asgn_tokens.select { |t| lines.include?(t.line) }
160
+ lines = all_relevant_assignment_lines(range.line)
161
+ tokens = assignment_tokens.select { |t| lines.include?(t.line) }
193
162
 
194
163
  columns = tokens.map { |t| align_column(t) }
195
164
  align_to = columns.max
@@ -209,17 +178,15 @@ module RuboCop
209
178
  end
210
179
  end
211
180
 
212
- def contiguous_assignment_lines(range)
213
- result = [range.line]
214
-
215
- range.line.downto(1) do |lineno|
216
- @asgn_lines.include?(lineno) ? result << lineno : break
217
- end
218
- range.line.upto(processed_source.lines.size) do |lineno|
219
- @asgn_lines.include?(lineno) ? result << lineno : break
220
- end
181
+ def all_relevant_assignment_lines(line_number)
182
+ last_line_number = processed_source.lines.size
221
183
 
222
- result.sort!
184
+ (
185
+ relevant_assignment_lines(line_number.downto(1)) +
186
+ relevant_assignment_lines(line_number.upto(last_line_number))
187
+ )
188
+ .uniq
189
+ .sort
223
190
  end
224
191
 
225
192
  def align_column(asgn_token)
@@ -231,12 +198,6 @@ module RuboCop
231
198
  asgn_token.pos.last_column - spaces + 1
232
199
  end
233
200
 
234
- def remove_optarg_equals(asgn_tokens, processed_source)
235
- optargs = processed_source.ast.each_node(:optarg)
236
- optarg_eql = optargs.map { |o| o.loc.operator.begin_pos }.to_set
237
- asgn_tokens.reject { |t| optarg_eql.include?(t.begin_pos) }
238
- end
239
-
240
201
  def allow_for_trailing_comments?
241
202
  cop_config['AllowBeforeTrailingComments']
242
203
  end