rubocop 1.5.0 → 1.7.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +52 -7
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +14 -0
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +21 -8
  7. data/lib/rubocop/config.rb +8 -5
  8. data/lib/rubocop/config_loader.rb +10 -6
  9. data/lib/rubocop/config_loader_resolver.rb +21 -4
  10. data/lib/rubocop/config_obsoletion.rb +64 -262
  11. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  12. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  13. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  14. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  17. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  18. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  20. data/lib/rubocop/config_validator.rb +11 -4
  21. data/lib/rubocop/cop/base.rb +17 -15
  22. data/lib/rubocop/cop/cop.rb +2 -2
  23. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  24. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  25. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  26. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  27. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
  28. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +1 -1
  29. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  30. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +26 -0
  31. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  32. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  33. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  34. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  35. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  36. data/lib/rubocop/cop/layout/space_before_brackets.rb +64 -0
  37. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  38. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  39. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  40. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  41. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  42. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  43. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  44. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  45. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  46. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  47. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  48. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  49. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  50. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  51. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  52. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  53. data/lib/rubocop/cop/registry.rb +10 -0
  54. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  55. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  56. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  57. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  58. data/lib/rubocop/cop/style/float_division.rb +44 -1
  59. data/lib/rubocop/cop/style/for.rb +2 -0
  60. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  61. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  62. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  63. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  64. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  65. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -0
  66. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  67. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  68. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  69. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  70. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  71. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  72. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  73. data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
  74. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  75. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  76. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  77. data/lib/rubocop/cop/style/single_line_methods.rb +4 -0
  78. data/lib/rubocop/cop/style/sole_nested_conditional.rb +24 -8
  79. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  80. data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
  81. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  82. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  83. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  84. data/lib/rubocop/cop/util.rb +3 -1
  85. data/lib/rubocop/ext/regexp_node.rb +31 -9
  86. data/lib/rubocop/ext/regexp_parser.rb +21 -3
  87. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  88. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  89. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  90. data/lib/rubocop/lockfile.rb +40 -0
  91. data/lib/rubocop/options.rb +9 -9
  92. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  93. data/lib/rubocop/rspec/expect_offense.rb +34 -22
  94. data/lib/rubocop/runner.rb +16 -1
  95. data/lib/rubocop/target_finder.rb +4 -2
  96. data/lib/rubocop/util.rb +16 -0
  97. data/lib/rubocop/version.rb +8 -2
  98. metadata +33 -5
@@ -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 feature_loaded?
19
+
20
+ affected_cops.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_cops.size > 1 ? "`#{department}` cops have" : "`#{old_name}` has",
27
+ gem: gem)
28
+ end
29
+
30
+ private
31
+
32
+ def affected_cops
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 feature_loaded?
40
+ config.loaded_features.include?(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