rubocop 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +5 -2
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +10 -0
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +16 -44
  7. data/lib/rubocop/config_obsoletion.rb +63 -263
  8. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  9. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  10. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  11. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  12. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  13. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  14. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  15. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  16. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  17. data/lib/rubocop/config_validator.rb +11 -4
  18. data/lib/rubocop/cop/base.rb +17 -15
  19. data/lib/rubocop/cop/cop.rb +2 -2
  20. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  21. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  22. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  23. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  24. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  25. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  26. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  27. data/lib/rubocop/cop/style/float_division.rb +44 -1
  28. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  29. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  30. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  31. data/lib/rubocop/cop/style/redundant_argument.rb +14 -1
  32. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  33. data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -6
  34. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  35. data/lib/rubocop/cop/style/string_concatenation.rb +19 -0
  36. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  37. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  38. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  39. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  40. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  41. data/lib/rubocop/lockfile.rb +40 -0
  42. data/lib/rubocop/version.rb +1 -1
  43. metadata +14 -3
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Encapsulation of a ConfigObsoletion rule for changing a parameter
6
+ # @api private
7
+ class ChangedEnforcedStyles < ParameterRule
8
+ BASE_MESSAGE = 'obsolete `%<parameter>s: %<value>s` (for `%<cop>s`) found in %<path>s'
9
+
10
+ def violated?
11
+ super && config[cop][parameter] == value
12
+ end
13
+
14
+ def message
15
+ base = format(BASE_MESSAGE,
16
+ parameter: parameter, value: value, cop: cop, path: smart_loaded_path)
17
+
18
+ if alternative
19
+ "#{base}\n`#{parameter}: #{value}` has been renamed to " \
20
+ "`#{parameter}: #{alternative.chomp}`."
21
+ else
22
+ "#{base}\n#{reason.chomp}"
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def value
29
+ metadata['value']
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Encapsulation of a ConfigObsoletion rule for changing a parameter
6
+ # @api private
7
+ class ChangedParameter < ParameterRule
8
+ BASE_MESSAGE = 'obsolete parameter `%<parameter>s` (for `%<cop>s`) found in %<path>s'
9
+
10
+ def message
11
+ base = format(BASE_MESSAGE, parameter: parameter, cop: cop, path: smart_loaded_path)
12
+
13
+ if alternative
14
+ "#{base}\n`#{parameter}` has been renamed to `#{alternative.chomp}`."
15
+ else
16
+ "#{base}\n#{reason.chomp}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Base class for ConfigObsoletion rules relating to cops
6
+ # @api private
7
+ class CopRule < Rule
8
+ attr_reader :old_name
9
+
10
+ def initialize(config, old_name)
11
+ super(config)
12
+ @old_name = old_name
13
+ end
14
+
15
+ def cop_rule?
16
+ true
17
+ end
18
+
19
+ def message
20
+ rule_message + "\n(obsolete configuration found in " \
21
+ "#{smart_loaded_path}, please update it)"
22
+ end
23
+
24
+ # Cop rules currently can only be failures, not warnings
25
+ def warning?
26
+ false
27
+ end
28
+
29
+ def violated?
30
+ config.key?(old_name) || config.key?(Cop::Badge.parse(old_name).cop_name)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Encapsulation of a ConfigObsoletion rule for splitting a cop's
6
+ # functionality into multiple new cops.
7
+ # @api private
8
+ class ExtractedCop < CopRule
9
+ attr_reader :gem, :department
10
+
11
+ def initialize(config, old_name, gem)
12
+ super(config, old_name)
13
+ @department, * = old_name.rpartition('/')
14
+ @gem = gem
15
+ end
16
+
17
+ def violated?
18
+ return false if gem_installed?
19
+
20
+ affected_gems.any?
21
+ end
22
+
23
+ def rule_message
24
+ msg = '%<name>s been extracted to the `%<gem>s` gem.'
25
+ format(msg,
26
+ name: affected_gems.size > 1 ? "`#{department}` cops have" : "`#{old_name}` has",
27
+ gem: gem)
28
+ end
29
+
30
+ private
31
+
32
+ def affected_gems
33
+ return old_name unless old_name.end_with?('*')
34
+
35
+ # Handle whole departments (expressed as `Department/*`)
36
+ config.keys.grep(Regexp.new("^#{department}"))
37
+ end
38
+
39
+ def gem_installed?
40
+ Lockfile.new.includes_gem?(gem)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Base class for ConfigObsoletion rules relating to parameters
6
+ # @api private
7
+ class ParameterRule < Rule
8
+ attr_reader :cop, :parameter, :metadata
9
+
10
+ def initialize(config, cop, parameter, metadata)
11
+ super(config)
12
+ @cop = cop
13
+ @parameter = parameter
14
+ @metadata = metadata
15
+ end
16
+
17
+ def parameter_rule?
18
+ true
19
+ end
20
+
21
+ def violated?
22
+ config[cop]&.key?(parameter)
23
+ end
24
+
25
+ def warning?
26
+ severity == 'warning'
27
+ end
28
+
29
+ private
30
+
31
+ def alternative
32
+ metadata['alternative']
33
+ end
34
+
35
+ def reason
36
+ metadata['reason']
37
+ end
38
+
39
+ def severity
40
+ metadata['severity']
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Encapsulation of a ConfigObsoletion rule for removing
6
+ # a previously defined cop.
7
+ # @api private
8
+ class RemovedCop < CopRule
9
+ attr_reader :old_name, :metadata
10
+
11
+ BASE_MESSAGE = 'The `%<old_name>s` cop has been removed'
12
+
13
+ def initialize(config, old_name, metadata)
14
+ super(config, old_name)
15
+ @metadata = metadata.is_a?(Hash) ? metadata : {}
16
+ end
17
+
18
+ def rule_message
19
+ base = format(BASE_MESSAGE, old_name: old_name)
20
+
21
+ if reason
22
+ "#{base} since #{reason.chomp}."
23
+ elsif alternatives
24
+ "#{base}. Please use #{to_sentence(alternatives, connector: 'and/or')} instead."
25
+ else
26
+ "#{base}."
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def reason
33
+ metadata['reason']
34
+ end
35
+
36
+ def alternatives
37
+ Array(metadata['alternatives']).map { |name| "`#{name}`" }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Encapsulation of a ConfigObsoletion rule for renaming
6
+ # a cop or moving it to a new department.
7
+ # @api private
8
+ class RenamedCop < CopRule
9
+ attr_reader :new_name
10
+
11
+ def initialize(config, old_name, new_name)
12
+ super(config, old_name)
13
+ @new_name = new_name
14
+ end
15
+
16
+ def rule_message
17
+ "The `#{old_name}` cop has been #{verb} to `#{new_name}`."
18
+ end
19
+
20
+ private
21
+
22
+ def moved?
23
+ old_badge = Cop::Badge.parse(old_name)
24
+ new_badge = Cop::Badge.parse(new_name)
25
+
26
+ old_badge.department != new_badge.department && old_badge.cop_name == new_badge.cop_name
27
+ end
28
+
29
+ def verb
30
+ moved? ? 'moved' : 'renamed'
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Abstract base class for ConfigObsoletion rules
6
+ # @api private
7
+ class Rule
8
+ def initialize(config)
9
+ @config = config
10
+ end
11
+
12
+ # Does this rule relate to cops?
13
+ def cop_rule?
14
+ false
15
+ end
16
+
17
+ # Does this rule relate to parameters?
18
+ def parameter_rule?
19
+ false
20
+ end
21
+
22
+ def violated?
23
+ raise NotImplementedError
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :config
29
+
30
+ def to_sentence(collection, connector: 'and')
31
+ return collection.first if collection.size == 1
32
+
33
+ [collection[0..-2].join(', '), collection[-1]].join(" #{connector} ")
34
+ end
35
+
36
+ def smart_loaded_path
37
+ PathUtil.smart_path(config.loaded_path)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class ConfigObsoletion
5
+ # Encapsulation of a ConfigObsoletion rule for splitting a cop's
6
+ # functionality into multiple new cops.
7
+ # @api private
8
+ class SplitCop < CopRule
9
+ attr_reader :metadata
10
+
11
+ def initialize(config, old_name, metadata)
12
+ super(config, old_name)
13
+ @metadata = metadata
14
+ end
15
+
16
+ def rule_message
17
+ "The `#{old_name}` cop has been split into #{to_sentence(alternatives)}."
18
+ end
19
+
20
+ private
21
+
22
+ def alternatives
23
+ Array(metadata['alternatives']).map { |name| "`#{name}`" }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -69,7 +69,7 @@ module RuboCop
69
69
  attr_reader :target_ruby
70
70
 
71
71
  def check_obsoletions
72
- @config_obsoletion.reject_obsolete_cops_and_parameters
72
+ @config_obsoletion.reject_obsolete!
73
73
  return unless @config_obsoletion.warnings.any?
74
74
 
75
75
  warn Rainbow("Warning: #{@config_obsoletion.warnings.join("\n")}").yellow
@@ -106,10 +106,17 @@ module RuboCop
106
106
  # to do so than to pass the value around to various methods.
107
107
  next if name == 'inherit_mode'
108
108
 
109
- unknown_cops << "unrecognized cop #{name} found in " \
110
- "#{smart_loaded_path}"
109
+ suggestions = NameSimilarity.find_similar_names(name, Cop::Registry.global.map(&:cop_name))
110
+ suggestion = "Did you mean `#{suggestions.join('`, `')}`?" if suggestions.any?
111
+
112
+ message = <<~MESSAGE.rstrip
113
+ unrecognized cop #{name} found in #{smart_loaded_path}
114
+ #{suggestion}
115
+ MESSAGE
116
+
117
+ unknown_cops << message
111
118
  end
112
- raise ValidationError, unknown_cops.join(', ') if unknown_cops.any?
119
+ raise ValidationError, unknown_cops.join("\n") if unknown_cops.any?
113
120
  end
114
121
 
115
122
  def validate_syntax_cop
@@ -288,13 +288,6 @@ module RuboCop
288
288
  @current_corrector&.merge!(corrector) if corrector
289
289
  end
290
290
 
291
- def correction_strategy
292
- return :unsupported unless correctable?
293
- return :uncorrected unless autocorrect?
294
-
295
- :attempt_correction
296
- end
297
-
298
291
  ### Reserved for Commissioner:
299
292
 
300
293
  def current_offense_locations
@@ -341,33 +334,42 @@ module RuboCop
341
334
 
342
335
  # @return [Symbol, Corrector] offense status
343
336
  def correct(range)
344
- status = correction_strategy
345
-
346
337
  if block_given?
347
338
  corrector = Corrector.new(self)
348
339
  yield corrector
349
- if !corrector.empty? && !self.class.support_autocorrect?
340
+ if corrector.empty?
341
+ corrector = nil
342
+ elsif !self.class.support_autocorrect?
350
343
  raise "The Cop #{name} must `extend AutoCorrector` to be able to autocorrect"
351
344
  end
352
345
  end
353
346
 
354
- status = attempt_correction(range, corrector) if status == :attempt_correction
347
+ [use_corrector(range, corrector), corrector]
348
+ end
355
349
 
356
- [status, corrector]
350
+ # @return [Symbol] offense status
351
+ def use_corrector(range, corrector)
352
+ if autocorrect?
353
+ attempt_correction(range, corrector)
354
+ elsif corrector
355
+ :uncorrected
356
+ else
357
+ :unsupported
358
+ end
357
359
  end
358
360
 
359
361
  # @return [Symbol] offense status
360
362
  def attempt_correction(range, corrector)
361
- if corrector && !corrector.empty?
363
+ if corrector
362
364
  status = :corrected
363
365
  elsif disable_uncorrectable?
364
366
  corrector = disable_uncorrectable(range)
365
367
  status = :corrected_with_todo
366
368
  else
367
- return :uncorrected
369
+ return :unsupported
368
370
  end
369
371
 
370
- apply_correction(corrector) if corrector
372
+ apply_correction(corrector)
371
373
  status
372
374
  end
373
375
 
@@ -27,7 +27,7 @@ module RuboCop
27
27
  def add_offense(node_or_range, location: :expression, message: nil, severity: nil, &block)
28
28
  @v0_argument = node_or_range
29
29
  range = find_location(node_or_range, location)
30
- if block.nil? && !autocorrect?
30
+ if block.nil? && !support_autocorrect?
31
31
  super(range, message: message, severity: severity)
32
32
  else
33
33
  super(range, message: message, severity: severity) do |corrector|
@@ -136,7 +136,7 @@ module RuboCop
136
136
  end
137
137
 
138
138
  def correction_lambda
139
- return unless correction_strategy == :attempt_correction && support_autocorrect?
139
+ return unless support_autocorrect?
140
140
 
141
141
  dedup_on_node(@v0_argument) do
142
142
  autocorrect(@v0_argument)
@@ -7,16 +7,14 @@ module RuboCop
7
7
  extend Util
8
8
 
9
9
  class << self
10
- def correct(node, style)
10
+ def correct(corrector, node, style)
11
11
  return if node.dstr_type?
12
12
 
13
- lambda do |corrector|
14
- str = node.str_content
15
- if style == :single_quotes
16
- corrector.replace(node, to_string_literal(str))
17
- else
18
- corrector.replace(node, str.inspect)
19
- end
13
+ str = node.str_content
14
+ if style == :single_quotes
15
+ corrector.replace(node, to_string_literal(str))
16
+ else
17
+ corrector.replace(node, str.inspect)
20
18
  end
21
19
  end
22
20
  end