rubocop 0.92.0 → 0.93.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +32 -0
  4. data/lib/rubocop.rb +3 -1
  5. data/lib/rubocop/cached_data.rb +2 -1
  6. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
  7. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
  8. data/lib/rubocop/cop/layout/dot_position.rb +6 -9
  9. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -7
  10. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  11. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
  12. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
  13. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
  14. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +15 -1
  15. data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
  16. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
  17. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  18. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  19. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +45 -0
  20. data/lib/rubocop/cop/metrics/block_length.rb +3 -1
  21. data/lib/rubocop/cop/metrics/class_length.rb +8 -6
  22. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  23. data/lib/rubocop/cop/offense.rb +15 -2
  24. data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
  25. data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
  26. data/lib/rubocop/cop/style/case_like_if.rb +20 -4
  27. data/lib/rubocop/cop/style/class_equality_comparison.rb +49 -0
  28. data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
  29. data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
  30. data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
  31. data/lib/rubocop/cop/style/for.rb +0 -4
  32. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  33. data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
  34. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
  35. data/lib/rubocop/cop/style/raise_args.rb +0 -3
  36. data/lib/rubocop/cop/style/redundant_begin.rb +26 -8
  37. data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
  38. data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
  39. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +39 -24
  40. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
  41. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  42. data/lib/rubocop/cop/variable_force/branch.rb +0 -4
  43. data/lib/rubocop/ext/regexp_node.rb +20 -4
  44. data/lib/rubocop/result_cache.rb +8 -2
  45. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  46. data/lib/rubocop/runner.rb +4 -4
  47. data/lib/rubocop/target_finder.rb +23 -25
  48. data/lib/rubocop/version.rb +1 -1
  49. metadata +10 -8
  50. data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
@@ -34,7 +34,6 @@ module RuboCop
34
34
  # /[+\-]\d/
35
35
  class RedundantRegexpEscape < Base
36
36
  include RangeHelp
37
- include RegexpLiteralHelp
38
37
  extend AutoCorrector
39
38
 
40
39
  MSG_REDUNDANT_ESCAPE = 'Redundant escape inside regexp literal'
@@ -59,9 +58,9 @@ module RuboCop
59
58
 
60
59
  def allowed_escape?(node, char, within_character_class)
61
60
  # Strictly speaking a few single-letter metachars are currently
62
- # unnecessary to "escape", e.g. g, i, E, F, but enumerating them is
61
+ # unnecessary to "escape", e.g. i, E, F, but enumerating them is
63
62
  # rather difficult, and their behaviour could change over time with
64
- # different versions of Ruby so that e.g. /\g/ != /g/
63
+ # different versions of Ruby so that e.g. /\i/ != /i/
65
64
  return true if /[[:alnum:]]/.match?(char)
66
65
  return true if ALLOWED_ALWAYS_ESCAPES.include?(char) || delimiter?(node, char)
67
66
 
@@ -82,19 +81,13 @@ module RuboCop
82
81
  end
83
82
 
84
83
  def each_escape(node)
85
- pattern_source(node).each_char.with_index.reduce(
86
- [nil, 0]
87
- ) do |(previous, char_class_depth), (current, index)|
88
- if previous == '\\'
89
- yield [current, index - 1, !char_class_depth.zero?]
90
-
91
- [nil, char_class_depth]
92
- elsif previous == '['
93
- [current, char_class_depth + 1]
94
- elsif current == ']'
95
- [current, char_class_depth - 1]
84
+ node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
85
+ yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
86
+
87
+ if expr.type == :set
88
+ char_class_depth + (event == :enter ? 1 : -1)
96
89
  else
97
- [current, char_class_depth]
90
+ char_class_depth
98
91
  end
99
92
  end
100
93
  end
@@ -87,7 +87,7 @@ module RuboCop
87
87
  if single_quoted?(part)
88
88
  part.value.gsub('\\') { '\\\\' }
89
89
  else
90
- escape_string(part.value)
90
+ part.value.inspect[1..-2]
91
91
  end
92
92
  else
93
93
  "\#{#{part.source}}"
@@ -20,8 +20,6 @@ module RuboCop
20
20
  nil
21
21
  end
22
22
 
23
- # rubocop:disable Metrics/BlockLength
24
-
25
23
  # Abstract base class for branch classes.
26
24
  # A branch represents a conditional branch in a scope.
27
25
  #
@@ -42,8 +40,6 @@ module RuboCop
42
40
  # do_something # no branch
43
41
  # end
44
42
  Base = Struct.new(:child_node, :scope) do
45
- # rubocop:enable Metrics/BlockLength
46
-
47
43
  def self.classes
48
44
  @classes ||= []
49
45
  end
@@ -17,11 +17,9 @@ module RuboCop
17
17
 
18
18
  # @return [Regexp::Expression::Root, nil]
19
19
  def parsed_tree
20
- return if interpolation?
21
-
22
- str = content
20
+ str = with_interpolations_blanked
23
21
  Ext::RegexpNode.parsed_cache[str] ||= begin
24
- Regexp::Parser.parse(str)
22
+ Regexp::Parser.parse(str, options: options)
25
23
  rescue StandardError
26
24
  nil
27
25
  end
@@ -40,6 +38,24 @@ module RuboCop
40
38
  self
41
39
  end
42
40
 
41
+ private
42
+
43
+ def with_interpolations_blanked
44
+ # Ignore the trailing regopt node
45
+ children[0...-1].map do |child|
46
+ source = child.source
47
+
48
+ # We don't want to consider the contents of interpolations as part of the pattern source,
49
+ # but need to preserve their width, to allow offsets to correctly line up with the
50
+ # original source: spaces have no effect, and preserve width.
51
+ if child.begin_type?
52
+ ' ' * source.length
53
+ else
54
+ source
55
+ end
56
+ end.join
57
+ end
58
+
43
59
  AST::RegexpNode.include self
44
60
  end
45
61
  end
@@ -95,6 +95,11 @@ module RuboCop
95
95
  context_checksum(team, options),
96
96
  file_checksum(file, config_store))
97
97
  @cached_data = CachedData.new(file)
98
+ @debug = options[:debug]
99
+ end
100
+
101
+ def debug?
102
+ @debug
98
103
  end
99
104
 
100
105
  def valid?
@@ -102,6 +107,7 @@ module RuboCop
102
107
  end
103
108
 
104
109
  def load
110
+ puts "Loading cache from #{@path}" if debug?
105
111
  @cached_data.from_json(IO.read(@path, encoding: Encoding::UTF_8))
106
112
  end
107
113
 
@@ -209,8 +215,8 @@ module RuboCop
209
215
  # The external dependency checksums are cached per RuboCop team so that
210
216
  # the checksums don't need to be recomputed for each file.
211
217
  def team_checksum(team)
212
- @checksum_by_team ||= {}
213
- @checksum_by_team[team.object_id] ||= team.external_dependency_checksum
218
+ @checksum_by_team ||= {}.compare_by_identity
219
+ @checksum_by_team[team] ||= team.external_dependency_checksum
214
220
  end
215
221
 
216
222
  # We combine team and options into a single "context" checksum to avoid
@@ -26,7 +26,7 @@ module CopHelper
26
26
  end
27
27
 
28
28
  def parse_source(source, file = nil)
29
- if file&.respond_to?(:write)
29
+ if file.respond_to?(:write)
30
30
  file.write(source)
31
31
  file.rewind
32
32
  file = file.path
@@ -324,8 +324,8 @@ module RuboCop
324
324
  end
325
325
 
326
326
  def mobilized_cop_classes(config)
327
- @mobilized_cop_classes ||= {}
328
- @mobilized_cop_classes[config.object_id] ||= begin
327
+ @mobilized_cop_classes ||= {}.compare_by_identity
328
+ @mobilized_cop_classes[config] ||= begin
329
329
  cop_classes = Cop::Registry.all
330
330
 
331
331
  OptionsValidator.new(@options).validate_cop_options
@@ -399,8 +399,8 @@ module RuboCop
399
399
  # otherwise dormant team that can be used for config- and option-
400
400
  # level caching in ResultCache.
401
401
  def standby_team(config)
402
- @team_by_config ||= {}
403
- @team_by_config[config.object_id] ||=
402
+ @team_by_config ||= {}.compare_by_identity
403
+ @team_by_config[config] ||=
404
404
  Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
405
405
  end
406
406
  end
@@ -81,34 +81,32 @@ module RuboCop
81
81
  # the top level directories that are excluded in configuration in the
82
82
  # normal way (dir/**/*).
83
83
  def find_files(base_dir, flags)
84
- wanted_toplevel_dirs = toplevel_dirs(base_dir, flags) -
85
- excluded_dirs(base_dir)
86
- wanted_toplevel_dirs.map! { |dir| dir << '/**/*' }
87
-
88
- pattern = if wanted_toplevel_dirs.empty?
89
- # We need this special case to avoid creating the pattern
90
- # /**/* which searches the entire file system.
91
- ["#{base_dir}/**/*"]
92
- else
93
- # Search the non-excluded top directories, but also add files
94
- # on the top level, which would otherwise not be found.
95
- wanted_toplevel_dirs.unshift("#{base_dir}/*")
84
+ # get all wanted directories first to improve speed of finding all files
85
+ exclude_pattern = combined_exclude_glob_patterns(base_dir)
86
+ dir_flags = flags | File::FNM_PATHNAME | File::FNM_EXTGLOB
87
+ patterns = wanted_dir_patterns(base_dir, exclude_pattern, dir_flags)
88
+ patterns.map! { |dir| File.join(dir, '*') }
89
+ # We need this special case to avoid creating the pattern
90
+ # /**/* which searches the entire file system.
91
+ patterns = [File.join(dir, '**/*')] if patterns.empty?
92
+
93
+ Dir.glob(patterns, flags).select { |path| FileTest.file?(path) }
94
+ end
95
+
96
+ def wanted_dir_patterns(base_dir, exclude_pattern, flags)
97
+ dirs = Dir.glob(File.join(base_dir, '*/'), flags)
98
+ .reject do |dir|
99
+ dir.end_with?('/./', '/../') || File.fnmatch?(exclude_pattern, dir, flags)
96
100
  end
97
- Dir.glob(pattern, flags).select { |path| FileTest.file?(path) }
101
+ dirs.flat_map { |dir| wanted_dir_patterns(dir, exclude_pattern, flags) }
102
+ .unshift(base_dir)
98
103
  end
99
104
 
100
- def toplevel_dirs(base_dir, flags)
101
- Dir.glob(File.join(base_dir, '*'), flags).select do |dir|
102
- File.directory?(dir) && !dir.end_with?('/.', '/..')
103
- end
104
- end
105
-
106
- def excluded_dirs(base_dir)
107
- all_cops_config = @config_store.for(base_dir).for_all_cops
108
- dir_tree_excludes = all_cops_config['Exclude'].select do |pattern|
109
- pattern.is_a?(String) && pattern.end_with?('/**/*')
110
- end
111
- dir_tree_excludes.map { |pattern| pattern.sub(%r{/\*\*/\*$}, '') }
105
+ def combined_exclude_glob_patterns(base_dir)
106
+ exclude = @config_store.for(base_dir).for_all_cops['Exclude']
107
+ patterns = exclude.select { |pattern| pattern.is_a?(String) && pattern.end_with?('/**/*') }
108
+ .map { |pattern| pattern.sub("#{base_dir}/", '') }
109
+ "#{base_dir}/{#{patterns.join(',')}}"
112
110
  end
113
111
 
114
112
  def ruby_extension?(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.92.0'
6
+ STRING = '0.93.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.92.0
4
+ version: 0.93.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-09-25 00:00:00.000000000 Z
13
+ date: 2020-10-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -66,14 +66,14 @@ dependencies:
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '1.7'
69
+ version: '1.8'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '1.7'
76
+ version: '1.8'
77
77
  - !ruby/object:Gem::Dependency
78
78
  name: rexml
79
79
  requirement: !ruby/object:Gem::Requirement
@@ -94,14 +94,14 @@ dependencies:
94
94
  requirements:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
- version: 0.5.0
97
+ version: 0.6.0
98
98
  type: :runtime
99
99
  prerelease: false
100
100
  version_requirements: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
- version: 0.5.0
104
+ version: 0.6.0
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: ruby-progressbar
107
107
  requirement: !ruby/object:Gem::Requirement
@@ -367,6 +367,7 @@ files:
367
367
  - lib/rubocop/cop/lint/float_comparison.rb
368
368
  - lib/rubocop/cop/lint/float_out_of_range.rb
369
369
  - lib/rubocop/cop/lint/format_parameter_mismatch.rb
370
+ - lib/rubocop/cop/lint/hash_compare_by_identity.rb
370
371
  - lib/rubocop/cop/lint/heredoc_method_call_position.rb
371
372
  - lib/rubocop/cop/lint/identity_comparison.rb
372
373
  - lib/rubocop/cop/lint/implicit_string_concatenation.rb
@@ -396,6 +397,7 @@ files:
396
397
  - lib/rubocop/cop/lint/redundant_cop_disable_directive.rb
397
398
  - lib/rubocop/cop/lint/redundant_cop_enable_directive.rb
398
399
  - lib/rubocop/cop/lint/redundant_require_statement.rb
400
+ - lib/rubocop/cop/lint/redundant_safe_navigation.rb
399
401
  - lib/rubocop/cop/lint/redundant_splat_expansion.rb
400
402
  - lib/rubocop/cop/lint/redundant_string_coercion.rb
401
403
  - lib/rubocop/cop/lint/redundant_with_index.rb
@@ -501,7 +503,6 @@ files:
501
503
  - lib/rubocop/cop/mixin/preferred_delimiters.rb
502
504
  - lib/rubocop/cop/mixin/range_help.rb
503
505
  - lib/rubocop/cop/mixin/rational_literal.rb
504
- - lib/rubocop/cop/mixin/regexp_literal_help.rb
505
506
  - lib/rubocop/cop/mixin/rescue_node.rb
506
507
  - lib/rubocop/cop/mixin/safe_assignment.rb
507
508
  - lib/rubocop/cop/mixin/space_after_punctuation.rb
@@ -559,6 +560,7 @@ files:
559
560
  - lib/rubocop/cop/style/character_literal.rb
560
561
  - lib/rubocop/cop/style/class_and_module_children.rb
561
562
  - lib/rubocop/cop/style/class_check.rb
563
+ - lib/rubocop/cop/style/class_equality_comparison.rb
562
564
  - lib/rubocop/cop/style/class_methods.rb
563
565
  - lib/rubocop/cop/style/class_methods_definitions.rb
564
566
  - lib/rubocop/cop/style/class_vars.rb
@@ -803,7 +805,7 @@ metadata:
803
805
  homepage_uri: https://rubocop.org/
804
806
  changelog_uri: https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md
805
807
  source_code_uri: https://github.com/rubocop-hq/rubocop/
806
- documentation_uri: https://docs.rubocop.org/rubocop/0.92/
808
+ documentation_uri: https://docs.rubocop.org/rubocop/0.93/
807
809
  bug_tracker_uri: https://github.com/rubocop-hq/rubocop/issues
808
810
  post_install_message:
809
811
  rdoc_options: []
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- # Common functionality for handling Regexp literals.
6
- module RegexpLiteralHelp
7
- private
8
-
9
- def freespace_mode_regexp?(node)
10
- regopt = node.children.find(&:regopt_type?)
11
-
12
- regopt.children.include?(:x)
13
- end
14
-
15
- def pattern_source(node)
16
- freespace_mode = freespace_mode_regexp?(node)
17
-
18
- node.children.reject(&:regopt_type?).map do |child|
19
- source_with_comments_and_interpolations_blanked(child, freespace_mode)
20
- end.join
21
- end
22
-
23
- def source_with_comments_and_interpolations_blanked(child, freespace_mode)
24
- source = child.source
25
-
26
- # We don't want to consider the contents of interpolations or free-space mode comments as
27
- # part of the pattern source, but need to preserve their width, to allow offsets to
28
- # correctly line up with the original source: spaces have no effect, and preserve width.
29
- if child.begin_type?
30
- replace_match_with_spaces(source, /.*/m) # replace all content
31
- elsif freespace_mode
32
- replace_match_with_spaces(source, /(?<!\\)#.*/) # replace any comments
33
- else
34
- source
35
- end
36
- end
37
-
38
- def replace_match_with_spaces(source, pattern)
39
- source.sub(pattern) { ' ' * Regexp.last_match[0].length }
40
- end
41
- end
42
- end
43
- end