rubocop 0.87.1 → 0.88.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/bin/rubocop-profile +31 -0
  4. data/config/default.yml +57 -6
  5. data/lib/rubocop.rb +6 -0
  6. data/lib/rubocop/cli.rb +2 -2
  7. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  8. data/lib/rubocop/config_loader.rb +20 -7
  9. data/lib/rubocop/config_store.rb +4 -0
  10. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  11. data/lib/rubocop/cop/badge.rb +1 -1
  12. data/lib/rubocop/cop/base.rb +12 -4
  13. data/lib/rubocop/cop/cop.rb +1 -1
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +26 -0
  15. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +6 -1
  16. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  17. data/lib/rubocop/cop/layout/end_alignment.rb +3 -2
  18. data/lib/rubocop/cop/layout/multiline_block_layout.rb +16 -5
  19. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -2
  20. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +27 -68
  21. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +3 -2
  22. data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +8 -2
  23. data/lib/rubocop/cop/lint/duplicate_elsif_condition.rb +39 -0
  24. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
  25. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +3 -2
  26. data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -1
  27. data/lib/rubocop/cop/lint/nested_method_definition.rb +13 -19
  28. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +67 -0
  29. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -3
  30. data/lib/rubocop/cop/style/accessor_grouping.rb +8 -1
  31. data/lib/rubocop/cop/style/array_coercion.rb +63 -0
  32. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +3 -2
  33. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +5 -4
  34. data/lib/rubocop/cop/style/case_like_if.rb +217 -0
  35. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  36. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  37. data/lib/rubocop/cop/style/exponential_notation.rb +6 -8
  38. data/lib/rubocop/cop/style/float_division.rb +7 -10
  39. data/lib/rubocop/cop/style/format_string_token.rb +5 -5
  40. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +62 -0
  41. data/lib/rubocop/cop/style/hash_like_case.rb +76 -0
  42. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -11
  43. data/lib/rubocop/cop/style/missing_else.rb +1 -11
  44. data/lib/rubocop/cop/style/numeric_predicate.rb +3 -4
  45. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -3
  46. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  47. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +50 -0
  48. data/lib/rubocop/cop/style/redundant_sort.rb +3 -2
  49. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +3 -2
  50. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +9 -32
  51. data/lib/rubocop/cop/variable_force/variable.rb +5 -3
  52. data/lib/rubocop/file_finder.rb +12 -12
  53. data/lib/rubocop/path_util.rb +2 -17
  54. data/lib/rubocop/result_cache.rb +12 -8
  55. data/lib/rubocop/rspec/expect_offense.rb +31 -5
  56. data/lib/rubocop/rspec/shared_contexts.rb +12 -9
  57. data/lib/rubocop/runner.rb +5 -6
  58. data/lib/rubocop/target_finder.rb +2 -2
  59. data/lib/rubocop/version.rb +1 -1
  60. metadata +9 -2
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module PathUtil
6
6
  module_function
7
7
 
8
- def relative_path(path, base_dir = PathUtil.pwd)
8
+ def relative_path(path, base_dir = Dir.pwd)
9
9
  # Optimization for the common case where path begins with the base
10
10
  # dir. Just cut off the first part.
11
11
  if path.start_with?(base_dir)
@@ -24,7 +24,7 @@ module RuboCop
24
24
 
25
25
  def smart_path(path)
26
26
  # Ideally, we calculate this relative to the project root.
27
- base_dir = PathUtil.pwd
27
+ base_dir = Dir.pwd
28
28
 
29
29
  if path.start_with? base_dir
30
30
  relative_path(path, base_dir)
@@ -54,21 +54,6 @@ module RuboCop
54
54
  %r{\A([A-Z]:)?/}i.match?(path)
55
55
  end
56
56
 
57
- def self.pwd
58
- @pwd ||= Dir.pwd
59
- end
60
-
61
- def self.reset_pwd
62
- @pwd = nil
63
- end
64
-
65
- def self.chdir(dir, &block)
66
- reset_pwd
67
- Dir.chdir(dir, &block)
68
- ensure
69
- reset_pwd
70
- end
71
-
72
57
  def hidden_file_in_not_hidden_dir?(pattern, path)
73
58
  File.fnmatch?(
74
59
  pattern, path,
@@ -33,7 +33,7 @@ module RuboCop
33
33
 
34
34
  def requires_file_removal?(file_count, config_store)
35
35
  file_count > 1 &&
36
- file_count > config_store.for_dir('.').for_all_cops['MaxFilesInCache']
36
+ file_count > config_store.for_pwd.for_all_cops['MaxFilesInCache']
37
37
  end
38
38
 
39
39
  def remove_oldest_files(files, dirs, cache_root, verbose)
@@ -60,7 +60,7 @@ module RuboCop
60
60
  end
61
61
 
62
62
  def self.cache_root(config_store)
63
- root = config_store.for_dir('.').for_all_cops['CacheRootDirectory']
63
+ root = config_store.for_pwd.for_all_cops['CacheRootDirectory']
64
64
  root ||= if ENV.key?('XDG_CACHE_HOME')
65
65
  # Include user ID in the path to make sure the user has write
66
66
  # access.
@@ -72,7 +72,7 @@ module RuboCop
72
72
  end
73
73
 
74
74
  def self.allow_symlinks_in_cache_location?(config_store)
75
- config_store.for_dir('.').for_all_cops['AllowSymlinksInCacheRootDirectory']
75
+ config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
76
76
  end
77
77
 
78
78
  def initialize(file, team, options, config_store, cache_root = nil)
@@ -158,6 +158,7 @@ module RuboCop
158
158
  end
159
159
 
160
160
  # The checksum of the rubocop program running the inspection.
161
+ # rubocop:disable Metrics/AbcSize
161
162
  def rubocop_checksum
162
163
  ResultCache.source_checksum ||=
163
164
  begin
@@ -168,13 +169,16 @@ module RuboCop
168
169
  # exe directory. A change to any of them could affect the cop output
169
170
  # so we include them in the cache hash.
170
171
  source_files = $LOADED_FEATURES + Find.find(exe_root).to_a
171
- sources = source_files
172
- .select { |path| File.file?(path) }
173
- .sort
174
- .map { |path| IO.read(path, encoding: Encoding::UTF_8) }
175
- Digest::SHA1.hexdigest(sources.join)
172
+
173
+ digest = Digest::SHA1.new
174
+ source_files
175
+ .select { |path| File.file?(path) }
176
+ .sort!
177
+ .each { |path| digest << File.mtime(path).to_s }
178
+ digest.hexdigest
176
179
  end
177
180
  end
181
+ # rubocop:enable Metrics/AbcSize
178
182
 
179
183
  # Return a hash of the options given at invocation, minus the ones that have
180
184
  # no effect on which offenses and disabled line ranges are found, and thus
@@ -73,19 +73,20 @@ module RuboCop
73
73
  # expect_no_corrections
74
74
  #
75
75
  # If your code has variables of different lengths, you can use `%{foo}`,
76
- # `^{foo}`, and `_{foo}` to format your template:
76
+ # `^{foo}`, and `_{foo}` to format your template; you can also abbreviate
77
+ # offense messages with `[...]`:
77
78
  #
78
79
  # %w[raise fail].each do |keyword|
79
80
  # expect_offense(<<~RUBY, keyword: keyword)
80
81
  # %{keyword}(RuntimeError, msg)
81
- # ^{keyword}^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
82
+ # ^{keyword}^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument [...]
82
83
  # RUBY
83
84
  #
84
85
  # %w[has_one has_many].each do |type|
85
86
  # expect_offense(<<~RUBY, type: type)
86
87
  # class Book
87
88
  # %{type} :chapter, foreign_key: 'book_id'
88
- # _{type} ^^^^^^^^^^^^^^^^^^^^^^ Specifying the default value is redundant.
89
+ # _{type} ^^^^^^^^^^^^^^^^^^^^^^ Specifying the default [...]
89
90
  # end
90
91
  # RUBY
91
92
  # end
@@ -102,6 +103,7 @@ module RuboCop
102
103
  module ExpectOffense
103
104
  def format_offense(source, **replacements)
104
105
  replacements.each do |keyword, value|
106
+ value = value.to_s
105
107
  source = source.gsub("%{#{keyword}}", value)
106
108
  .gsub("^{#{keyword}}", '^' * value.size)
107
109
  .gsub("_{#{keyword}}", ' ' * value.size)
@@ -132,7 +134,7 @@ module RuboCop
132
134
  actual_annotations =
133
135
  expected_annotations.with_offense_annotations(offenses)
134
136
 
135
- expect(actual_annotations.to_s).to eq(expected_annotations.to_s)
137
+ expect(actual_annotations).to eq(expected_annotations)
136
138
  expect(offenses.map(&:severity).uniq).to eq([severity]) if severity
137
139
  end
138
140
 
@@ -188,6 +190,7 @@ module RuboCop
188
190
  # Parsed representation of code annotated with the `^^^ Message` style
189
191
  class AnnotatedSource
190
192
  ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) /.freeze
193
+ ABBREV = "[...]\n"
191
194
 
192
195
  # @param annotated_source [String] string passed to the matchers
193
196
  #
@@ -206,6 +209,7 @@ module RuboCop
206
209
  source << source_line
207
210
  end
208
211
  end
212
+ annotations.each { |a| a[0] = 1 } if source.empty?
209
213
 
210
214
  new(source, annotations)
211
215
  end
@@ -221,6 +225,27 @@ module RuboCop
221
225
  @annotations = annotations.sort.freeze
222
226
  end
223
227
 
228
+ def ==(other)
229
+ other.is_a?(self.class) &&
230
+ other.lines == lines &&
231
+ match_annotations?(other)
232
+ end
233
+
234
+ # Dirty hack: expectations with [...] are rewritten when they match
235
+ # This way the diff is clean.
236
+ def match_annotations?(other)
237
+ annotations.zip(other.annotations) do |(_actual_line, actual_annotation),
238
+ (_expected_line, expected_annotation)|
239
+ if expected_annotation&.end_with?(ABBREV)
240
+ if actual_annotation.start_with?(expected_annotation[0...-ABBREV.length])
241
+ expected_annotation.replace(actual_annotation)
242
+ end
243
+ end
244
+ end
245
+
246
+ annotations == other.annotations
247
+ end
248
+
224
249
  # Construct annotated source string (like what we parse)
225
250
  #
226
251
  # Reconstruct a deterministic annotated source string. This is
@@ -253,6 +278,7 @@ module RuboCop
253
278
 
254
279
  reconstructed.join
255
280
  end
281
+ alias inspect to_s
256
282
 
257
283
  # Return the plain source code without annotations
258
284
  #
@@ -279,7 +305,7 @@ module RuboCop
279
305
  self.class.new(lines, offense_annotations)
280
306
  end
281
307
 
282
- private
308
+ protected
283
309
 
284
310
  attr_reader :lines, :annotations
285
311
  end
@@ -12,19 +12,22 @@ RSpec.shared_context 'isolated environment', :isolated_environment do
12
12
  # get mismatched pathnames when loading config files later on.
13
13
  tmpdir = File.realpath(tmpdir)
14
14
 
15
+ virtual_home = File.expand_path(File.join(tmpdir, 'home'))
16
+ Dir.mkdir(virtual_home)
17
+ ENV['HOME'] = virtual_home
18
+ ENV.delete('XDG_CONFIG_HOME')
19
+
20
+ base_dir = example.metadata[:project_inside_home] ? virtual_home : tmpdir
21
+ root = example.metadata[:root]
22
+ working_dir = root ? File.join(base_dir, 'work', root) : File.join(base_dir, 'work')
23
+
15
24
  # Make upwards search for .rubocop.yml files stop at this directory.
16
- RuboCop::FileFinder.root_level = tmpdir
25
+ RuboCop::FileFinder.root_level = working_dir
17
26
 
18
27
  begin
19
- virtual_home = File.expand_path(File.join(tmpdir, 'home'))
20
- Dir.mkdir(virtual_home)
21
- ENV['HOME'] = virtual_home
22
- ENV.delete('XDG_CONFIG_HOME')
23
-
24
- working_dir = File.join(tmpdir, 'work')
25
- Dir.mkdir(working_dir)
28
+ FileUtils.mkdir_p(working_dir)
26
29
 
27
- RuboCop::PathUtil.chdir(working_dir) do
30
+ Dir.chdir(working_dir) do
28
31
  example.run
29
32
  end
30
33
  ensure
@@ -118,8 +118,7 @@ module RuboCop
118
118
 
119
119
  def file_offenses(file)
120
120
  file_offense_cache(file) do
121
- source = get_processed_source(file)
122
- source, offenses = do_inspection_loop(file, source)
121
+ source, offenses = do_inspection_loop(file)
123
122
  offenses = add_redundant_disables(file, offenses.compact.sort, source)
124
123
  offenses.sort.reject(&:disabled?).freeze
125
124
  end
@@ -159,8 +158,7 @@ module RuboCop
159
158
  # Do one extra inspection loop if any redundant disables were
160
159
  # removed. This is done in order to find rubocop:enable directives that
161
160
  # have now become useless.
162
- _source, new_offenses = do_inspection_loop(file,
163
- get_processed_source(file))
161
+ _source, new_offenses = do_inspection_loop(file)
164
162
  offenses |= new_offenses
165
163
  end
166
164
  end
@@ -213,7 +211,7 @@ module RuboCop
213
211
  @cached_run ||=
214
212
  (@options[:cache] == 'true' ||
215
213
  @options[:cache] != 'false' &&
216
- @config_store.for_dir(Dir.pwd).for_all_cops['UseCache']) &&
214
+ @config_store.for_pwd.for_all_cops['UseCache']) &&
217
215
  # When running --auto-gen-config, there's some processing done in the
218
216
  # cops related to calculating the Max parameters for Metrics cops. We
219
217
  # need to do that processing and cannot use caching.
@@ -232,7 +230,8 @@ module RuboCop
232
230
  cache.save(offenses)
233
231
  end
234
232
 
235
- def do_inspection_loop(file, processed_source)
233
+ def do_inspection_loop(file)
234
+ processed_source = get_processed_source(file)
236
235
  offenses = []
237
236
 
238
237
  # When running with --auto-correct, we need to inspect the file (which
@@ -132,7 +132,7 @@ module RuboCop
132
132
  end
133
133
 
134
134
  def all_cops_include
135
- @config_store.for('.').for_all_cops['Include'].map(&:to_s)
135
+ @config_store.for_pwd.for_all_cops['Include'].map(&:to_s)
136
136
  end
137
137
 
138
138
  def ruby_executable?(file)
@@ -160,7 +160,7 @@ module RuboCop
160
160
  end
161
161
 
162
162
  def configured_include?(file)
163
- @config_store.for('.').file_to_include?(file)
163
+ @config_store.for_pwd.file_to_include?(file)
164
164
  end
165
165
 
166
166
  def included_file?(file)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.87.1'
6
+ STRING = '0.88.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.87.1
4
+ version: 0.88.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2020-07-07 00:00:00.000000000 Z
13
+ date: 2020-07-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -178,6 +178,7 @@ files:
178
178
  - assets/logo.png
179
179
  - assets/output.html.erb
180
180
  - bin/console
181
+ - bin/rubocop-profile
181
182
  - bin/setup
182
183
  - config/default.yml
183
184
  - exe/rubocop
@@ -347,6 +348,7 @@ files:
347
348
  - lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb
348
349
  - lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb
349
350
  - lib/rubocop/cop/lint/duplicate_case_condition.rb
351
+ - lib/rubocop/cop/lint/duplicate_elsif_condition.rb
350
352
  - lib/rubocop/cop/lint/duplicate_hash_key.rb
351
353
  - lib/rubocop/cop/lint/duplicate_methods.rb
352
354
  - lib/rubocop/cop/lint/each_with_object_argument.rb
@@ -529,6 +531,7 @@ files:
529
531
  - lib/rubocop/cop/style/accessor_grouping.rb
530
532
  - lib/rubocop/cop/style/alias.rb
531
533
  - lib/rubocop/cop/style/and_or.rb
534
+ - lib/rubocop/cop/style/array_coercion.rb
532
535
  - lib/rubocop/cop/style/array_join.rb
533
536
  - lib/rubocop/cop/style/ascii_comments.rb
534
537
  - lib/rubocop/cop/style/attr.rb
@@ -539,6 +542,7 @@ files:
539
542
  - lib/rubocop/cop/style/block_comments.rb
540
543
  - lib/rubocop/cop/style/block_delimiters.rb
541
544
  - lib/rubocop/cop/style/case_equality.rb
545
+ - lib/rubocop/cop/style/case_like_if.rb
542
546
  - lib/rubocop/cop/style/character_literal.rb
543
547
  - lib/rubocop/cop/style/class_and_module_children.rb
544
548
  - lib/rubocop/cop/style/class_check.rb
@@ -582,7 +586,9 @@ files:
582
586
  - lib/rubocop/cop/style/frozen_string_literal_comment.rb
583
587
  - lib/rubocop/cop/style/global_vars.rb
584
588
  - lib/rubocop/cop/style/guard_clause.rb
589
+ - lib/rubocop/cop/style/hash_as_last_array_item.rb
585
590
  - lib/rubocop/cop/style/hash_each_methods.rb
591
+ - lib/rubocop/cop/style/hash_like_case.rb
586
592
  - lib/rubocop/cop/style/hash_syntax.rb
587
593
  - lib/rubocop/cop/style/hash_transform_keys.rb
588
594
  - lib/rubocop/cop/style/hash_transform_values.rb
@@ -654,6 +660,7 @@ files:
654
660
  - lib/rubocop/cop/style/redundant_conditional.rb
655
661
  - lib/rubocop/cop/style/redundant_exception.rb
656
662
  - lib/rubocop/cop/style/redundant_fetch_block.rb
663
+ - lib/rubocop/cop/style/redundant_file_extension_in_require.rb
657
664
  - lib/rubocop/cop/style/redundant_freeze.rb
658
665
  - lib/rubocop/cop/style/redundant_interpolation.rb
659
666
  - lib/rubocop/cop/style/redundant_parentheses.rb