rubocop 1.4.1 → 1.6.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +54 -11
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +14 -0
  6. data/lib/rubocop/cli.rb +5 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
  8. data/lib/rubocop/config_loader.rb +1 -1
  9. data/lib/rubocop/config_loader_resolver.rb +5 -1
  10. data/lib/rubocop/config_obsoletion.rb +65 -247
  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 +18 -4
  21. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  22. data/lib/rubocop/cop/base.rb +17 -15
  23. data/lib/rubocop/cop/cop.rb +2 -2
  24. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  25. data/lib/rubocop/cop/generator.rb +1 -1
  26. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +3 -3
  27. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  29. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  30. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  34. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  35. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +1 -1
  36. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  37. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  38. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +7 -2
  39. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  40. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  41. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  42. data/lib/rubocop/cop/metrics/parameter_lists.rb +64 -1
  43. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  44. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  45. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  46. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  47. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -2
  48. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  49. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  50. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  51. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  52. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  53. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  54. data/lib/rubocop/cop/style/and_or.rb +10 -0
  55. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  56. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  57. data/lib/rubocop/cop/style/float_division.rb +44 -1
  58. data/lib/rubocop/cop/style/format_string.rb +8 -3
  59. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  60. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  61. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  62. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  63. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  64. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  65. data/lib/rubocop/cop/style/redundant_argument.rb +17 -2
  66. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  67. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  68. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  69. data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
  70. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  71. data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
  72. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  73. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  74. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  75. data/lib/rubocop/core_ext/hash.rb +20 -0
  76. data/lib/rubocop/ext/regexp_node.rb +29 -12
  77. data/lib/rubocop/ext/regexp_parser.rb +20 -9
  78. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  79. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  80. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  81. data/lib/rubocop/lockfile.rb +40 -0
  82. data/lib/rubocop/version.rb +1 -1
  83. metadata +32 -5
@@ -69,10 +69,14 @@ module RuboCop
69
69
  if @options[:auto_gen_config]
70
70
  run_command(:auto_gen_config)
71
71
  else
72
- run_command(:execute_runner)
72
+ run_command(:execute_runner).tap { suggest_extensions }
73
73
  end
74
74
  end
75
75
 
76
+ def suggest_extensions
77
+ run_command(:suggest_extensions)
78
+ end
79
+
76
80
  def validate_options_vs_config
77
81
  if @options[:parallel] &&
78
82
  !@config_store.for_pwd.for_all_cops['UseCache']
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class CLI
5
+ module Command
6
+ # Suggest RuboCop extensions to install based on Gemfile dependencies.
7
+ # Only primary dependencies are evaluated, so if a dependency depends on a
8
+ # gem with an extension, it is not suggested. However, if an extension is
9
+ # a transitive dependency, it will not be suggested.
10
+ # @api private
11
+ class SuggestExtensions < Base
12
+ # Combination of short and long formatter names.
13
+ INCLUDED_FORMATTERS = %w[p progress fu fuubar pa pacman].freeze
14
+
15
+ self.command_name = :suggest_extensions
16
+
17
+ def run
18
+ return if skip? || extensions.none?
19
+
20
+ puts
21
+ puts 'Tip: Based on detected gems, the following '\
22
+ 'RuboCop extension libraries might be helpful:'
23
+
24
+ extensions.sort.each do |extension|
25
+ puts " * #{extension} (http://github.com/rubocop-hq/#{extension})"
26
+ end
27
+
28
+ puts
29
+ puts 'You can opt out of this message by adding the following to your config '\
30
+ '(see https://docs.rubocop.org/rubocop/extensions.html#extension-suggestions '\
31
+ 'for more options):'
32
+ puts ' AllCops:'
33
+ puts ' SuggestExtensions: false'
34
+
35
+ puts if @options[:display_time]
36
+ end
37
+
38
+ private
39
+
40
+ def skip?
41
+ # Disable outputting the notification:
42
+ # 1. On CI
43
+ # 2. When given RuboCop options that it doesn't make sense for
44
+ # 3. For all formatters except specified in `INCLUDED_FORMATTERS'`
45
+ ENV['CI'] ||
46
+ @options[:only] || @options[:debug] || @options[:list_target_files] || @options[:out] ||
47
+ !INCLUDED_FORMATTERS.include?(current_formatter)
48
+ end
49
+
50
+ def current_formatter
51
+ @options[:format] || @config_store.for_pwd.for_all_cops['DefaultFormatter'] || 'p'
52
+ end
53
+
54
+ def extensions
55
+ return [] unless lockfile.dependencies.any?
56
+
57
+ extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions'] || {}
58
+ extensions.select { |_, v| (Array(v) & dependent_gems).any? }.keys - installed_gems
59
+ end
60
+
61
+ def lockfile
62
+ @lockfile ||= Lockfile.new
63
+ end
64
+
65
+ def dependent_gems
66
+ lockfile.dependencies.map(&:name)
67
+ end
68
+
69
+ def installed_gems
70
+ lockfile.gems.map(&:name)
71
+ end
72
+
73
+ def puts(*args)
74
+ output = (@options[:stderr] ? $stderr : $stdout)
75
+ output.puts(*args)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  merge_with_default(config, config_file).tap do |merged_config|
112
- warn_on_pending_cops(merged_config.pending_cops) unless possible_new_cops?(config)
112
+ warn_on_pending_cops(merged_config.pending_cops) unless possible_new_cops?(merged_config)
113
113
  end
114
114
  end
115
115
 
@@ -92,7 +92,7 @@ module RuboCop
92
92
  keys_appearing_in_both.each do |key|
93
93
  if opts[:unset_nil] && derived_hash[key].nil?
94
94
  result.delete(key)
95
- elsif base_hash[key].is_a?(Hash)
95
+ elsif merge_hashes?(base_hash, derived_hash, key)
96
96
  result[key] = merge(base_hash[key], derived_hash[key], **opts)
97
97
  elsif should_union?(base_hash, key, opts[:inherit_mode])
98
98
  result[key] = base_hash[key] | derived_hash[key]
@@ -164,6 +164,10 @@ module RuboCop
164
164
  inherit_mode['merge'].include?(key)
165
165
  end
166
166
 
167
+ def merge_hashes?(base_hash, derived_hash, key)
168
+ base_hash[key].is_a?(Hash) && derived_hash[key].is_a?(Hash)
169
+ end
170
+
167
171
  def base_configs(path, inherit_from, file)
168
172
  configs = Array(inherit_from).compact.map do |f|
169
173
  ConfigLoader.load_file(inherited_file(path, f, file))
@@ -4,223 +4,40 @@ module RuboCop
4
4
  # This class handles obsolete configuration.
5
5
  # @api private
6
6
  class ConfigObsoletion
7
- RENAMED_COPS = {
8
- 'Layout/AlignArguments' => 'Layout/ArgumentAlignment',
9
- 'Layout/AlignArray' => 'Layout/ArrayAlignment',
10
- 'Layout/AlignHash' => 'Layout/HashAlignment',
11
- 'Layout/AlignParameters' => 'Layout/ParameterAlignment',
12
- 'Layout/IndentArray' => 'Layout/FirstArrayElementIndentation',
13
- 'Layout/IndentAssignment' => 'Layout/AssignmentIndentation',
14
- 'Layout/IndentFirstArgument' => 'Layout/FirstArgumentIndentation',
15
- 'Layout/IndentFirstArrayElement' => 'Layout/FirstArrayElementIndentation',
16
- 'Layout/IndentFirstHashElement' => 'Layout/FirstHashElementIndentation',
17
- 'Layout/IndentFirstParameter' => 'Layout/FirstParameterIndentation',
18
- 'Layout/IndentHash' => 'Layout/FirstHashElementIndentation',
19
- 'Layout/IndentHeredoc' => 'Layout/HeredocIndentation',
20
- 'Layout/LeadingBlankLines' => 'Layout/LeadingEmptyLines',
21
- 'Layout/Tab' => 'Layout/IndentationStyle',
22
- 'Layout/TrailingBlankLines' => 'Layout/TrailingEmptyLines',
23
- 'Lint/DuplicatedKey' => 'Lint/DuplicateHashKey',
24
- 'Lint/EndInMethod' => 'Style/EndBlock',
25
- 'Lint/HandleExceptions' => 'Lint/SuppressedException',
26
- 'Lint/MultipleCompare' => 'Lint/MultipleComparison',
27
- 'Lint/StringConversionInInterpolation' => 'Lint/RedundantStringCoercion',
28
- 'Lint/UnneededCopDisableDirective' => 'Lint/RedundantCopDisableDirective',
29
- 'Lint/UnneededCopEnableDirective' => 'Lint/RedundantCopEnableDirective',
30
- 'Lint/UnneededRequireStatement' => 'Lint/RedundantRequireStatement',
31
- 'Lint/UnneededSplatExpansion' => 'Lint/RedundantSplatExpansion',
32
- 'Naming/UncommunicativeBlockParamName' => 'Naming/BlockParameterName',
33
- 'Naming/UncommunicativeMethodParamName' => 'Naming/MethodParameterName',
34
- 'Style/DeprecatedHashMethods' => 'Style/PreferredHashMethods',
35
- 'Style/MethodCallParentheses' => 'Style/MethodCallWithoutArgsParentheses',
36
- 'Style/OpMethod' => 'Naming/BinaryOperatorParameterName',
37
- 'Style/SingleSpaceBeforeFirstArg' => 'Layout/SpaceBeforeFirstArg',
38
- 'Style/UnneededCapitalW' => 'Style/RedundantCapitalW',
39
- 'Style/UnneededCondition' => 'Style/RedundantCondition',
40
- 'Style/UnneededInterpolation' => 'Style/RedundantInterpolation',
41
- 'Style/UnneededPercentQ' => 'Style/RedundantPercentQ',
42
- 'Style/UnneededSort' => 'Style/RedundantSort'
43
- }.map do |old_name, new_name|
44
- [old_name, "The `#{old_name}` cop has been renamed to `#{new_name}`."]
45
- end
46
-
47
- MOVED_COPS = {
48
- 'Security' => 'Lint/Eval',
49
- 'Naming' => %w[Style/ClassAndModuleCamelCase Style/ConstantName
50
- Style/FileName Style/MethodName Style/PredicateName
51
- Style/VariableName Style/VariableNumber
52
- Style/AccessorMethodName Style/AsciiIdentifiers],
53
- 'Layout' => %w[Lint/BlockAlignment Lint/EndAlignment
54
- Lint/DefEndAlignment Metrics/LineLength],
55
- 'Lint' => 'Style/FlipFlop'
56
- }.map do |new_department, old_names|
57
- Array(old_names).map do |old_name|
58
- [old_name, "The `#{old_name}` cop has been moved to " \
59
- "`#{new_department}/#{old_name.split('/').last}`."]
60
- end
61
- end
62
-
63
- REMOVED_COPS = {
64
- 'Layout/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
65
- 'Layout/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
66
- 'Lint/RescueWithoutErrorClass' => 'Style/RescueStandardError',
67
- 'Style/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword',
68
- 'Style/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword',
69
- 'Style/TrailingComma' => 'Style/TrailingCommaInArguments, ' \
70
- 'Style/TrailingCommaInArrayLiteral, and/or ' \
71
- 'Style/TrailingCommaInHashLiteral',
72
- 'Style/TrailingCommaInLiteral' => 'Style/TrailingCommaInArrayLiteral ' \
73
- 'and/or ' \
74
- 'Style/TrailingCommaInHashLiteral',
75
- 'Style/BracesAroundHashParameters' => nil
76
- }.map do |old_name, other_cops|
77
- if other_cops
78
- more = ". Please use #{other_cops} instead".gsub(%r{[A-Z]\w+/\w+},
79
- '`\&`')
7
+ DEFAULT_RULES_FILE = File.join(ConfigLoader::RUBOCOP_HOME, 'config', 'obsoletion.yml')
8
+ COP_RULE_CLASSES = {
9
+ 'renamed' => RenamedCop,
10
+ 'removed' => RemovedCop,
11
+ 'split' => SplitCop,
12
+ 'extracted' => ExtractedCop
13
+ }.freeze
14
+ PARAMETER_RULE_CLASSES = {
15
+ 'changed_parameters' => ChangedParameter,
16
+ 'changed_enforced_styles' => ChangedEnforcedStyles
17
+ }.freeze
18
+
19
+ attr_reader :rules, :warnings
20
+
21
+ class << self
22
+ attr_accessor :files
23
+
24
+ def legacy_cop_names
25
+ # Used by DepartmentName#qualified_legacy_cop_name
26
+ new(Config.new).rules.select(&:cop_rule?).map(&:old_name)
80
27
  end
81
- [old_name, "The `#{old_name}` cop has been removed#{more}."]
82
- end
83
-
84
- REMOVED_COPS_WITH_REASON = {
85
- 'Lint/InvalidCharacterLiteral' => 'it was never being actually triggered',
86
- 'Lint/SpaceBeforeFirstArg' =>
87
- 'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \
88
- '`Layout/SpaceBeforeFirstArg` instead',
89
- 'Style/MethodMissingSuper' => 'it has been superseded by `Lint/MissingSuper`. Please use ' \
90
- '`Lint/MissingSuper` instead',
91
- 'Lint/UselessComparison' => 'it has been superseded by '\
92
- '`Lint/BinaryOperatorWithIdenticalOperands`. Please use '\
93
- '`Lint/BinaryOperatorWithIdenticalOperands` instead'
94
- }.map do |cop_name, reason|
95
- [cop_name, "The `#{cop_name}` cop has been removed since #{reason}."]
96
28
  end
97
29
 
98
- SPLIT_COPS = {
99
- 'Style/MethodMissing' =>
100
- 'The `Style/MethodMissing` cop has been split into ' \
101
- '`Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.'
102
- }.to_a
103
-
104
- OBSOLETE_COPS = Hash[*(RENAMED_COPS + MOVED_COPS + REMOVED_COPS +
105
- REMOVED_COPS_WITH_REASON + SPLIT_COPS).flatten]
106
-
107
- OBSOLETE_PARAMETERS = [
108
- {
109
- cops: %w[Layout/SpaceAroundOperators Style/SpaceAroundOperators],
110
- parameters: 'MultiSpaceAllowedForOperators',
111
- alternative: 'If your intention was to allow extra spaces for ' \
112
- 'alignment, please use AllowForAlignment: true instead.'
113
- },
114
- {
115
- cops: 'Style/Encoding',
116
- parameters: %w[EnforcedStyle SupportedStyles
117
- AutoCorrectEncodingComment],
118
- alternative: 'Style/Encoding no longer supports styles. ' \
119
- 'The "never" behavior is always assumed.'
120
- },
121
- {
122
- cops: 'Style/IfUnlessModifier',
123
- parameters: 'MaxLineLength',
124
- alternative: '`Style/IfUnlessModifier: MaxLineLength` has been ' \
125
- 'removed. Use `Layout/LineLength: Max` instead'
126
- },
127
- {
128
- cops: 'Style/WhileUntilModifier',
129
- parameters: 'MaxLineLength',
130
- alternative: '`Style/WhileUntilModifier: MaxLineLength` has been ' \
131
- 'removed. Use `Layout/LineLength: Max` instead'
132
- },
133
- {
134
- cops: 'AllCops',
135
- parameters: 'RunRailsCops',
136
- alternative: "Use the following configuration instead:\n" \
137
- "Rails:\n Enabled: true"
138
- },
139
- {
140
- cops: 'Layout/CaseIndentation',
141
- parameters: 'IndentWhenRelativeTo',
142
- alternative: '`IndentWhenRelativeTo` has been renamed to ' \
143
- '`EnforcedStyle`'
144
- },
145
- {
146
- cops: %w[Lint/BlockAlignment Layout/BlockAlignment Lint/EndAlignment
147
- Layout/EndAlignment Lint/DefEndAlignment
148
- Layout/DefEndAlignment],
149
- parameters: 'AlignWith',
150
- alternative: '`AlignWith` has been renamed to `EnforcedStyleAlignWith`'
151
- },
152
- {
153
- cops: 'Rails/UniqBeforePluck',
154
- parameters: 'EnforcedMode',
155
- alternative: '`EnforcedMode` has been renamed to `EnforcedStyle`'
156
- },
157
- {
158
- cops: 'Style/MethodCallWithArgsParentheses',
159
- parameters: 'IgnoredMethodPatterns',
160
- alternative: '`IgnoredMethodPatterns` has been renamed to ' \
161
- '`IgnoredPatterns`'
162
- },
163
- {
164
- cops: %w[Performance/Count Performance/Detect],
165
- parameters: 'SafeMode',
166
- alternative: '`SafeMode` has been removed. ' \
167
- 'Use `SafeAutoCorrect` instead.'
168
- },
169
- {
170
- cops: 'Bundler/GemComment',
171
- parameters: 'Whitelist',
172
- alternative: '`Whitelist` has been renamed to `IgnoredGems`.'
173
- },
174
- {
175
- cops: %w[
176
- Lint/SafeNavigationChain Lint/SafeNavigationConsistency
177
- Style/NestedParenthesizedCalls Style/SafeNavigation
178
- Style/TrivialAccessors
179
- ],
180
- parameters: 'Whitelist',
181
- alternative: '`Whitelist` has been renamed to `AllowedMethods`.'
182
- },
183
- {
184
- cops: 'Style/IpAddresses',
185
- parameters: 'Whitelist',
186
- alternative: '`Whitelist` has been renamed to `AllowedAddresses`.'
187
- },
188
- {
189
- cops: 'Naming/HeredocDelimiterNaming',
190
- parameters: 'Blacklist',
191
- alternative: '`Blacklist` has been renamed to `ForbiddenDelimiters`.'
192
- },
193
- {
194
- cops: 'Naming/PredicateName',
195
- parameters: 'NamePrefixBlacklist',
196
- alternative: '`NamePrefixBlacklist` has been renamed to ' \
197
- '`ForbiddenPrefixes`.'
198
- },
199
- {
200
- cops: 'Naming/PredicateName',
201
- parameters: 'NameWhitelist',
202
- alternative: '`NameWhitelist` has been renamed to ' \
203
- '`AllowedMethods`.'
204
- }
205
- ].freeze
206
-
207
- OBSOLETE_ENFORCED_STYLES = [
208
- {
209
- cop: 'Layout/IndentationConsistency',
210
- parameter: 'EnforcedStyle',
211
- enforced_style: 'rails',
212
- alternative: '`EnforcedStyle: rails` has been renamed to ' \
213
- '`EnforcedStyle: indented_internal_methods`'
214
- }
215
- ].freeze
30
+ # Can be extended by extension libraries to add their own obsoletions
31
+ self.files = [DEFAULT_RULES_FILE]
216
32
 
217
33
  def initialize(config)
218
34
  @config = config
35
+ @rules = load_rules
36
+ @warnings = []
219
37
  end
220
38
 
221
- def reject_obsolete_cops_and_parameters
222
- messages = [obsolete_cops, obsolete_parameters,
223
- obsolete_enforced_style].flatten.compact
39
+ def reject_obsolete!
40
+ messages = obsoletions.flatten.compact
224
41
  return if messages.empty?
225
42
 
226
43
  raise ValidationError, messages.join("\n")
@@ -228,56 +45,57 @@ module RuboCop
228
45
 
229
46
  private
230
47
 
231
- def obsolete_cops
232
- OBSOLETE_COPS.map do |cop_name, message|
233
- next unless @config.key?(cop_name) ||
234
- @config.key?(Cop::Badge.parse(cop_name).cop_name)
235
-
236
- message + "\n(obsolete configuration found in " \
237
- "#{smart_loaded_path}, please update it)"
238
- end
239
- end
240
-
241
- def obsolete_enforced_style
242
- OBSOLETE_ENFORCED_STYLES.map do |params|
243
- obsolete_enforced_style_message(params[:cop], params[:parameter],
244
- params[:enforced_style],
245
- params[:alternative])
48
+ # Default rules for obsoletions are in config/obsoletion.yml
49
+ # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
50
+ def load_rules
51
+ rules = self.class.files.each_with_object({}) do |filename, hash|
52
+ hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
53
+ first.merge(second)
54
+ end
246
55
  end
247
- end
248
-
249
- def obsolete_enforced_style_message(cop, param, enforced_style, alternative)
250
- style = @config[cop]&.detect { |key, _| key.start_with?(param) }
251
56
 
252
- return unless style && style[1] == enforced_style
57
+ cop_rules = rules.slice(*COP_RULE_CLASSES.keys)
58
+ parameter_rules = rules.slice(*PARAMETER_RULE_CLASSES.keys)
253
59
 
254
- "obsolete `#{param}: #{enforced_style}` (for #{cop}) found in " \
255
- "#{smart_loaded_path}\n#{alternative}"
60
+ load_cop_rules(cop_rules).concat(load_parameter_rules(parameter_rules))
256
61
  end
257
62
 
258
- def obsolete_parameters
259
- OBSOLETE_PARAMETERS.map do |params|
260
- obsolete_parameter_message(params[:cops], params[:parameters],
261
- params[:alternative])
63
+ # Cop rules are keyed by the name of the original cop
64
+ def load_cop_rules(rules)
65
+ rules.flat_map do |rule_type, data|
66
+ data.map do |configuration|
67
+ COP_RULE_CLASSES[rule_type].new(@config, *configuration)
68
+ end
262
69
  end
263
70
  end
264
71
 
265
- def obsolete_parameter_message(cops, parameters, alternative)
266
- Array(cops).map do |cop|
267
- obsolete_parameters = Array(parameters).select do |param|
268
- @config[cop]&.key?(param)
269
- end
270
- next if obsolete_parameters.empty?
271
-
272
- obsolete_parameters.map do |parameter|
273
- "obsolete parameter #{parameter} (for #{cop}) found in " \
274
- "#{smart_loaded_path}\n#{alternative}"
72
+ # Parameter rules may apply to multiple cops and multiple parameters
73
+ # and are given as an array. Each combination is turned into a separate
74
+ # rule object.
75
+ def load_parameter_rules(rules)
76
+ rules.flat_map do |rule_type, data|
77
+ data.flat_map do |configuration|
78
+ cops = Array(configuration['cops'])
79
+ parameters = Array(configuration['parameters'])
80
+
81
+ cops.product(parameters).map do |cop, parameter|
82
+ PARAMETER_RULE_CLASSES[rule_type].new(@config, cop, parameter, configuration)
83
+ end
275
84
  end
276
85
  end
277
86
  end
278
87
 
279
- def smart_loaded_path
280
- PathUtil.smart_path(@config.loaded_path)
88
+ def obsoletions
89
+ rules.map do |rule|
90
+ next unless rule.violated?
91
+
92
+ if rule.warning?
93
+ @warnings.push(rule.message)
94
+ next
95
+ end
96
+
97
+ rule.message
98
+ end
281
99
  end
282
100
  end
283
101
  end