rubocop 1.4.2 → 1.5.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +47 -7
  4. data/lib/rubocop.rb +4 -0
  5. data/lib/rubocop/cli.rb +5 -1
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +67 -0
  7. data/lib/rubocop/config_loader.rb +1 -1
  8. data/lib/rubocop/config_loader_resolver.rb +5 -1
  9. data/lib/rubocop/config_obsoletion.rb +21 -3
  10. data/lib/rubocop/config_validator.rb +8 -1
  11. data/lib/rubocop/cop/generator.rb +1 -1
  12. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  13. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  14. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  15. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +1 -1
  16. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  17. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +8 -5
  18. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  19. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  20. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  21. data/lib/rubocop/cop/metrics/parameter_lists.rb +64 -1
  22. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  23. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  24. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  25. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  26. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  27. data/lib/rubocop/cop/style/and_or.rb +10 -0
  28. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  29. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  30. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  31. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  32. data/lib/rubocop/cop/style/redundant_argument.rb +1 -1
  33. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  34. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  35. data/lib/rubocop/cop/style/sole_nested_conditional.rb +49 -3
  36. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  37. data/lib/rubocop/core_ext/hash.rb +20 -0
  38. data/lib/rubocop/ext/regexp_node.rb +5 -10
  39. data/lib/rubocop/ext/regexp_parser.rb +2 -9
  40. data/lib/rubocop/version.rb +1 -1
  41. metadata +11 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea427ad9cf52b48c6d81ea6b730474acccb359cef988e0e00020a358f1e4662e
4
- data.tar.gz: fb7383af86d50886bef707d52c835e0af030f002cbd22f0864fab28494f0f592
3
+ metadata.gz: 4ce46e11fac05ae40731d9a49b0c4229aa719d395a3f946b294965c52513ad1b
4
+ data.tar.gz: 56c6f908f370d96d011287d67172e41c9a8a3a21748fb04d5235d0f957ffd64f
5
5
  SHA512:
6
- metadata.gz: 1b35dbc1cb654f63c19fe863c6e1cc64778a94ac3b961505a565fa8202c20ea8a45a75347c8166456a5e5d420072c30516a51f31c0b76c456ecd53eade62d743
7
- data.tar.gz: aa36afc87c4bef92a5032e26c81a31c6a26623f1257180b55db693cd56f2926130639b99220786c6f7708db374ab57eff90d280aa0d4519c7d9c651059efe95b
6
+ metadata.gz: f58d45c385e3fcccee94a8c258dd9536fb768c8ae069201411bb22f3c33dac0806b1d177f7f5562a27b71ae25ab3896917c06c29703c1f1c7d276506442069c6
7
+ data.tar.gz: ca55f537a662481c1337f6301d162074138c76a36c3332715aa2304ef2b67363df4b026ec1aa4dabe6e9c6b7833c0ed48edca99ea249a152a6a563a6242beeac
data/README.md CHANGED
@@ -51,7 +51,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
51
51
  in your `Gemfile`:
52
52
 
53
53
  ```rb
54
- gem 'rubocop', '~> 1.4', require: false
54
+ gem 'rubocop', '~> 1.5', require: false
55
55
  ```
56
56
 
57
57
  See [versioning](https://docs.rubocop.org/rubocop/1.0/versioning.html) for further details.
@@ -139,6 +139,16 @@ AllCops:
139
139
  # from the lock file.) If the Ruby version is still unresolved, RuboCop will
140
140
  # use the oldest officially supported Ruby version (currently Ruby 2.4).
141
141
  TargetRubyVersion: ~
142
+ # Determines if a notification for extension libraries should be shown when
143
+ # rubocop is run. Keys are the name of the extension, and values are an array
144
+ # of gems in the Gemfile that the extension is suggested for, if not already
145
+ # included.
146
+ SuggestExtensions:
147
+ rubocop-rails: [rails]
148
+ rubocop-rspec: [rspec, rspec-rails]
149
+ rubocop-minitest: [minitest]
150
+ rubocop-sequel: [sequel]
151
+ rubocop-rake: [rake]
142
152
 
143
153
  #################### Bundler ###############################
144
154
 
@@ -1998,6 +2008,23 @@ Lint/UnderscorePrefixedVariableName:
1998
2008
  VersionAdded: '0.21'
1999
2009
  AllowKeywordBlockArguments: false
2000
2010
 
2011
+ Lint/UnexpectedBlockArity:
2012
+ Description: 'Looks for blocks that have fewer arguments that the calling method expects.'
2013
+ Enabled: pending
2014
+ Safe: false
2015
+ VersionAdded: '1.5'
2016
+ Methods:
2017
+ chunk_while: 2
2018
+ each_with_index: 2
2019
+ each_with_object: 2
2020
+ inject: 2
2021
+ max: 2
2022
+ min: 2
2023
+ minmax: 2
2024
+ reduce: 2
2025
+ slice_when: 2
2026
+ sort: 2
2027
+
2001
2028
  Lint/UnifiedInteger:
2002
2029
  Description: 'Use Integer instead of Fixnum or Bignum.'
2003
2030
  Enabled: true
@@ -2007,6 +2034,7 @@ Lint/UnmodifiedReduceAccumulator:
2007
2034
  Description: Checks for `reduce` or `inject` blocks that do not update the accumulator each iteration.
2008
2035
  Enabled: pending
2009
2036
  VersionAdded: '1.1'
2037
+ VersionChanged: '1.5'
2010
2038
 
2011
2039
  Lint/UnreachableCode:
2012
2040
  Description: 'Unreachable code.'
@@ -2110,21 +2138,23 @@ Metrics/AbcSize:
2110
2138
  - https://en.wikipedia.org/wiki/ABC_Software_Metric
2111
2139
  Enabled: true
2112
2140
  VersionAdded: '0.27'
2113
- VersionChanged: '0.81'
2141
+ VersionChanged: '1.5'
2114
2142
  # The ABC size is a calculated magnitude, so this number can be an Integer or
2115
2143
  # a Float.
2116
2144
  IgnoredMethods: []
2145
+ CountRepeatedAttributes: true
2117
2146
  Max: 17
2118
2147
 
2119
2148
  Metrics/BlockLength:
2120
2149
  Description: 'Avoid long blocks with many lines.'
2121
2150
  Enabled: true
2122
2151
  VersionAdded: '0.44'
2123
- VersionChanged: '0.87'
2152
+ VersionChanged: '1.5'
2124
2153
  CountComments: false # count full line comments?
2125
2154
  Max: 25
2126
2155
  CountAsOne: []
2127
- ExcludedMethods:
2156
+ ExcludedMethods: [] # deprecated, retained for backwards compatibility
2157
+ IgnoredMethods:
2128
2158
  # By default, exclude the `#refine` method, as it tends to have larger
2129
2159
  # associated blocks.
2130
2160
  - refine
@@ -2165,11 +2195,12 @@ Metrics/MethodLength:
2165
2195
  StyleGuide: '#short-methods'
2166
2196
  Enabled: true
2167
2197
  VersionAdded: '0.25'
2168
- VersionChanged: '0.87'
2198
+ VersionChanged: '1.5'
2169
2199
  CountComments: false # count full line comments?
2170
2200
  Max: 10
2171
2201
  CountAsOne: []
2172
- ExcludedMethods: []
2202
+ ExcludedMethods: [] # deprecated, retained for backwards compatibility
2203
+ IgnoredMethods: []
2173
2204
 
2174
2205
  Metrics/ModuleLength:
2175
2206
  Description: 'Avoid modules longer than 100 lines of code.'
@@ -2185,8 +2216,10 @@ Metrics/ParameterLists:
2185
2216
  StyleGuide: '#too-many-params'
2186
2217
  Enabled: true
2187
2218
  VersionAdded: '0.25'
2219
+ VersionChanged: '1.5'
2188
2220
  Max: 5
2189
2221
  CountKeywordArgs: true
2222
+ MaxOptionalParameters: 3
2190
2223
 
2191
2224
  Metrics/PerceivedComplexity:
2192
2225
  Description: >-
@@ -2464,7 +2497,13 @@ Naming/VariableNumber:
2464
2497
  - non_integer
2465
2498
  CheckMethodNames: true
2466
2499
  CheckSymbols: true
2467
- AllowedIdentifiers: []
2500
+ AllowedIdentifiers:
2501
+ - capture3 # Open3.capture3
2502
+ - iso8601 # Time#iso8601
2503
+ - rfc1123_date # CGI.rfc1123_date
2504
+ - rfc822 # Time#rfc822
2505
+ - rfc2822 # Time#rfc2822
2506
+ - rfc3339 # DateTime.rfc3339
2468
2507
 
2469
2508
  #################### Security ##############################
2470
2509
 
@@ -4262,6 +4301,7 @@ Style/SoleNestedConditional:
4262
4301
  which can be merged into outer conditional node.
4263
4302
  Enabled: true
4264
4303
  VersionAdded: '0.89'
4304
+ VersionChanged: '1.5'
4265
4305
  AllowModifier: false
4266
4306
 
4267
4307
  Style/SpecialGlobalVars:
@@ -4394,7 +4434,7 @@ Style/SymbolProc:
4394
4434
  Enabled: true
4395
4435
  Safe: false
4396
4436
  VersionAdded: '0.26'
4397
- VersionChanged: '0.64'
4437
+ VersionChanged: '1.5'
4398
4438
  # A list of method names to be ignored by the check.
4399
4439
  # The names should be fairly unique, otherwise you'll end up ignoring lots of code.
4400
4440
  IgnoredMethods:
@@ -18,6 +18,7 @@ require_relative 'rubocop/ext/regexp_node'
18
18
  require_relative 'rubocop/ext/regexp_parser'
19
19
 
20
20
  require_relative 'rubocop/core_ext/string'
21
+ require_relative 'rubocop/core_ext/hash'
21
22
  require_relative 'rubocop/ext/processed_source'
22
23
 
23
24
  require_relative 'rubocop/path_util'
@@ -88,6 +89,7 @@ require_relative 'rubocop/cop/mixin/interpolation'
88
89
  require_relative 'rubocop/cop/mixin/line_length_help'
89
90
  require_relative 'rubocop/cop/mixin/match_range'
90
91
  require_relative 'rubocop/cop/metrics/utils/repeated_csend_discount'
92
+ require_relative 'rubocop/cop/metrics/utils/repeated_attribute_discount'
91
93
  require_relative 'rubocop/cop/mixin/method_complexity'
92
94
  require_relative 'rubocop/cop/mixin/method_preference'
93
95
  require_relative 'rubocop/cop/mixin/min_body_length'
@@ -341,6 +343,7 @@ require_relative 'rubocop/cop/lint/to_json'
341
343
  require_relative 'rubocop/cop/lint/top_level_return_with_argument'
342
344
  require_relative 'rubocop/cop/lint/trailing_comma_in_attribute_declaration'
343
345
  require_relative 'rubocop/cop/lint/underscore_prefixed_variable_name'
346
+ require_relative 'rubocop/cop/lint/unexpected_block_arity'
344
347
  require_relative 'rubocop/cop/lint/unified_integer'
345
348
  require_relative 'rubocop/cop/lint/unmodified_reduce_accumulator'
346
349
  require_relative 'rubocop/cop/lint/unreachable_code'
@@ -646,6 +649,7 @@ require_relative 'rubocop/cli/command/auto_genenerate_config'
646
649
  require_relative 'rubocop/cli/command/execute_runner'
647
650
  require_relative 'rubocop/cli/command/init_dotfile'
648
651
  require_relative 'rubocop/cli/command/show_cops'
652
+ require_relative 'rubocop/cli/command/suggest_extensions'
649
653
  require_relative 'rubocop/cli/command/version'
650
654
  require_relative 'rubocop/config_regeneration'
651
655
  require_relative 'rubocop/options'
@@ -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,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class CLI
5
+ module Command
6
+ # Run all the selected cops and report the result.
7
+ # @api private
8
+ class SuggestExtensions < Base
9
+ # Combination of short and long formatter names.
10
+ INCLUDED_FORMATTERS = %w[p progress fu fuubar pa pacman].freeze
11
+
12
+ self.command_name = :suggest_extensions
13
+
14
+ def run
15
+ return if skip? || extensions.none?
16
+
17
+ puts
18
+ puts 'Tip: Based on detected gems, the following '\
19
+ 'RuboCop extension libraries might be helpful:'
20
+
21
+ extensions.each do |extension|
22
+ puts " * #{extension} (http://github.com/rubocop-hq/#{extension})"
23
+ end
24
+
25
+ puts
26
+ puts 'You can opt out of this message by adding the following to your config:'
27
+ puts ' AllCops:'
28
+ puts ' SuggestExtensions: false'
29
+ puts if @options[:display_time]
30
+ end
31
+
32
+ private
33
+
34
+ def skip?
35
+ # Disable outputting the notification:
36
+ # 1. On CI
37
+ # 2. When given RuboCop options that it doesn't make sense for
38
+ # 3. For all formatters except specified in `INCLUDED_FORMATTERS'`
39
+ ENV['CI'] ||
40
+ @options[:only] || @options[:debug] || @options[:list_target_files] || @options[:out] ||
41
+ !INCLUDED_FORMATTERS.include?(current_formatter)
42
+ end
43
+
44
+ def current_formatter
45
+ @options[:format] || @config_store.for_pwd.for_all_cops['DefaultFormatter'] || 'p'
46
+ end
47
+
48
+ def extensions
49
+ extensions = @config_store.for_pwd.for_all_cops['SuggestExtensions']
50
+ return [] unless extensions
51
+
52
+ extensions.select { |_, v| (v & dependent_gems).any? }.keys - dependent_gems
53
+ end
54
+
55
+ def dependent_gems
56
+ # This only includes gems in Gemfile, not in lockfile
57
+ Bundler.load.dependencies.map(&:name)
58
+ end
59
+
60
+ def puts(*args)
61
+ output = (@options[:stderr] ? $stderr : $stdout)
62
+ output.puts(*args)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ 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))
@@ -104,6 +104,7 @@ module RuboCop
104
104
  OBSOLETE_COPS = Hash[*(RENAMED_COPS + MOVED_COPS + REMOVED_COPS +
105
105
  REMOVED_COPS_WITH_REASON + SPLIT_COPS).flatten]
106
106
 
107
+ # Parameters can be deprecated but not disabled by setting `severity: :warning`
107
108
  OBSOLETE_PARAMETERS = [
108
109
  {
109
110
  cops: %w[Layout/SpaceAroundOperators Style/SpaceAroundOperators],
@@ -201,6 +202,12 @@ module RuboCop
201
202
  parameters: 'NameWhitelist',
202
203
  alternative: '`NameWhitelist` has been renamed to ' \
203
204
  '`AllowedMethods`.'
205
+ },
206
+ {
207
+ cops: %w[Metrics/BlockLength Metrics/MethodLength],
208
+ parameters: 'ExcludedMethods',
209
+ alternative: '`ExcludedMethods` has been renamed to `IgnoredMethods`.',
210
+ severity: :warning
204
211
  }
205
212
  ].freeze
206
213
 
@@ -214,8 +221,11 @@ module RuboCop
214
221
  }
215
222
  ].freeze
216
223
 
224
+ attr_reader :warnings
225
+
217
226
  def initialize(config)
218
227
  @config = config
228
+ @warnings = []
219
229
  end
220
230
 
221
231
  def reject_obsolete_cops_and_parameters
@@ -256,9 +266,17 @@ module RuboCop
256
266
  end
257
267
 
258
268
  def obsolete_parameters
259
- OBSOLETE_PARAMETERS.map do |params|
260
- obsolete_parameter_message(params[:cops], params[:parameters],
261
- params[:alternative])
269
+ OBSOLETE_PARAMETERS.collect do |params|
270
+ messages = obsolete_parameter_message(params[:cops], params[:parameters],
271
+ params[:alternative])
272
+
273
+ # Warnings are collected separately and not added to the error message
274
+ if messages && params.fetch(:severity, :error) == :warning
275
+ @warnings.concat(messages)
276
+ next
277
+ end
278
+
279
+ messages
262
280
  end
263
281
  end
264
282
 
@@ -42,7 +42,7 @@ module RuboCop
42
42
  ConfigLoader.default_configuration.key?(key)
43
43
  end
44
44
 
45
- @config_obsoletion.reject_obsolete_cops_and_parameters
45
+ check_obsoletions
46
46
 
47
47
  alert_about_unrecognized_cops(invalid_cop_names)
48
48
  check_target_ruby
@@ -68,6 +68,13 @@ module RuboCop
68
68
 
69
69
  attr_reader :target_ruby
70
70
 
71
+ def check_obsoletions
72
+ @config_obsoletion.reject_obsolete_cops_and_parameters
73
+ return unless @config_obsoletion.warnings.any?
74
+
75
+ warn Rainbow("Warning: #{@config_obsoletion.warnings.join("\n")}").yellow
76
+ end
77
+
71
78
  def check_target_ruby
72
79
  return if target_ruby.supported?
73
80
 
@@ -139,7 +139,7 @@ module RuboCop
139
139
  badge: badge,
140
140
  version_added: version_added)
141
141
 
142
- injector.inject do
142
+ injector.inject do # rubocop:disable Lint/UnexpectedBlockArity
143
143
  output.puts(format(CONFIGURATION_ADDED_MESSAGE,
144
144
  configuration_file_path: config_file_path))
145
145
  end
@@ -45,7 +45,8 @@ module RuboCop
45
45
  MSG = 'Empty line detected around arguments.'
46
46
 
47
47
  def on_send(node)
48
- return if node.single_line? || node.arguments.empty?
48
+ return if node.single_line? || node.arguments.empty? ||
49
+ receiver_and_method_call_on_different_lines?(node)
49
50
 
50
51
  extra_lines(node) do |range|
51
52
  add_offense(range) do |corrector|
@@ -57,6 +58,10 @@ module RuboCop
57
58
 
58
59
  private
59
60
 
61
+ def receiver_and_method_call_on_different_lines?(node)
62
+ node.receiver && node.receiver.loc.last_line != node.loc.selector.line
63
+ end
64
+
60
65
  def empty_lines(node)
61
66
  lines = processed_lines(node)
62
67
  lines.select! { |code, _| code.empty? }
@@ -37,14 +37,14 @@ module RuboCop
37
37
  # # good
38
38
  # puts 'Hello' # Return character is CR+LF on all platfoms.
39
39
  #
40
- class EndOfLine < Cop
40
+ class EndOfLine < Base
41
41
  include ConfigurableEnforcedStyle
42
42
  include RangeHelp
43
43
 
44
44
  MSG_DETECTED = 'Carriage return character detected.'
45
45
  MSG_MISSING = 'Carriage return character missing.'
46
46
 
47
- def investigate(processed_source)
47
+ def on_new_investigation
48
48
  last_line = last_line(processed_source)
49
49
 
50
50
  processed_source.raw_source.each_line.with_index do |line, index|
@@ -54,9 +54,9 @@ module RuboCop
54
54
  next unless msg
55
55
  next if unimportant_missing_cr?(index, last_line, line)
56
56
 
57
- range =
58
- source_range(processed_source.buffer, index + 1, 0, line.length)
59
- add_offense(nil, location: range, message: msg)
57
+ range = source_range(processed_source.buffer, index + 1, 0, line.length)
58
+
59
+ add_offense(range, message: msg)
60
60
  # Usually there will be carriage return characters on all or none
61
61
  # of the lines in a file, so we report only one offense.
62
62
  break
@@ -207,8 +207,13 @@ module RuboCop
207
207
  PATTERN
208
208
 
209
209
  def base_range(send_node, arg_node)
210
- range_between(send_node.source_range.begin_pos,
211
- arg_node.source_range.begin_pos)
210
+ parent = send_node.parent
211
+ start_node = if parent && (parent.splat_type? || parent.kwsplat_type?)
212
+ send_node.parent
213
+ else
214
+ send_node
215
+ end
216
+ range_between(start_node.source_range.begin_pos, arg_node.source_range.begin_pos)
212
217
  end
213
218
 
214
219
  # Returns the column of the given range. For single line ranges, this