rubocop 0.92.0 → 0.93.0

Sign up to get free protection for your applications and to get access to all the features.
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