rubocop 0.86.0 → 0.87.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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +46 -4
  4. data/lib/rubocop.rb +7 -1
  5. data/lib/rubocop/cli.rb +0 -2
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +40 -5
  7. data/lib/rubocop/cli/command/show_cops.rb +1 -1
  8. data/lib/rubocop/config_loader.rb +22 -62
  9. data/lib/rubocop/config_obsoletion.rb +0 -1
  10. data/lib/rubocop/cop/autocorrect_logic.rb +13 -23
  11. data/lib/rubocop/cop/base.rb +399 -0
  12. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +10 -20
  13. data/lib/rubocop/cop/commissioner.rb +48 -50
  14. data/lib/rubocop/cop/cop.rb +85 -236
  15. data/lib/rubocop/cop/corrector.rb +38 -115
  16. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
  17. data/lib/rubocop/cop/generator.rb +1 -1
  18. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +11 -14
  19. data/lib/rubocop/cop/layout/case_indentation.rb +18 -19
  20. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -8
  21. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -0
  22. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -2
  23. data/lib/rubocop/cop/layout/multiline_block_layout.rb +0 -1
  24. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +19 -25
  25. data/lib/rubocop/cop/legacy/corrections_proxy.rb +49 -0
  26. data/lib/rubocop/cop/legacy/corrector.rb +29 -0
  27. data/lib/rubocop/cop/lint/interpolation_check.rb +13 -0
  28. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  29. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  30. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -3
  31. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  32. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -23
  33. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +2 -2
  34. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +8 -0
  35. data/lib/rubocop/cop/lint/syntax.rb +11 -26
  36. data/lib/rubocop/cop/lint/unused_method_argument.rb +1 -1
  37. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  38. data/lib/rubocop/cop/metrics/block_length.rb +22 -0
  39. data/lib/rubocop/cop/metrics/class_length.rb +25 -2
  40. data/lib/rubocop/cop/metrics/method_length.rb +23 -0
  41. data/lib/rubocop/cop/metrics/module_length.rb +25 -2
  42. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +129 -0
  43. data/lib/rubocop/cop/mixin/allowed_methods.rb +19 -0
  44. data/lib/rubocop/cop/mixin/auto_corrector.rb +12 -0
  45. data/lib/rubocop/cop/mixin/code_length.rb +4 -0
  46. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  47. data/lib/rubocop/cop/mixin/enforce_superclass.rb +3 -1
  48. data/lib/rubocop/cop/mixin/nil_methods.rb +3 -5
  49. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +6 -1
  50. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -2
  51. data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -13
  52. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +4 -2
  53. data/lib/rubocop/cop/naming/ascii_identifiers.rb +27 -4
  54. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +2 -2
  55. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  56. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  57. data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
  58. data/lib/rubocop/cop/naming/variable_name.rb +1 -1
  59. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  60. data/lib/rubocop/cop/offense.rb +16 -2
  61. data/lib/rubocop/cop/style/accessor_grouping.rb +136 -0
  62. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +121 -0
  63. data/lib/rubocop/cop/style/class_vars.rb +21 -0
  64. data/lib/rubocop/cop/style/date_time.rb +1 -1
  65. data/lib/rubocop/cop/style/dir.rb +2 -2
  66. data/lib/rubocop/cop/style/empty_literal.rb +5 -5
  67. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
  68. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -0
  69. data/lib/rubocop/cop/style/multiline_block_chain.rb +10 -1
  70. data/lib/rubocop/cop/style/mutable_constant.rb +4 -4
  71. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -5
  72. data/lib/rubocop/cop/style/proc.rb +1 -1
  73. data/lib/rubocop/cop/style/random_with_offset.rb +4 -10
  74. data/lib/rubocop/cop/style/redundant_assignment.rb +117 -0
  75. data/lib/rubocop/cop/style/redundant_exception.rb +14 -10
  76. data/lib/rubocop/cop/style/redundant_fetch_block.rb +26 -7
  77. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  78. data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
  79. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -1
  80. data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -1
  81. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  82. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  83. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -2
  84. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  85. data/lib/rubocop/cop/style/trivial_accessors.rb +8 -7
  86. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -2
  87. data/lib/rubocop/cop/team.rb +97 -81
  88. data/lib/rubocop/cop/utils/format_string.rb +1 -2
  89. data/lib/rubocop/name_similarity.rb +1 -3
  90. data/lib/rubocop/options.rb +15 -8
  91. data/lib/rubocop/rake_task.rb +6 -9
  92. data/lib/rubocop/rspec/cop_helper.rb +4 -4
  93. data/lib/rubocop/rspec/expect_offense.rb +10 -16
  94. data/lib/rubocop/rspec/shared_contexts.rb +7 -7
  95. data/lib/rubocop/runner.rb +31 -29
  96. data/lib/rubocop/target_ruby.rb +1 -1
  97. data/lib/rubocop/version.rb +1 -1
  98. metadata +15 -7
  99. data/lib/rubocop/cop/mixin/classish_length.rb +0 -37
@@ -6,8 +6,31 @@ module RuboCop
6
6
  # This cop checks if the length a module exceeds some maximum value.
7
7
  # Comment lines can optionally be ignored.
8
8
  # The maximum allowed length is configurable.
9
+ #
10
+ # You can set literals you want to fold with `CountAsOne`.
11
+ # Available are: 'array', 'hash', and 'heredoc'. Each literal
12
+ # will be counted as one line regardless of its actual size.
13
+ #
14
+ # @example CountAsOne: ['array', 'heredoc']
15
+ #
16
+ # module M
17
+ # ARRAY = [ # +1
18
+ # 1,
19
+ # 2
20
+ # ]
21
+ #
22
+ # HASH = { # +3
23
+ # key: 'value'
24
+ # }
25
+ #
26
+ # MSG = <<~HEREDOC # +1
27
+ # Heredoc
28
+ # content.
29
+ # HEREDOC
30
+ # end # 5 points
31
+ #
9
32
  class ModuleLength < Cop
10
- include ClassishLength
33
+ include TooManyLines
11
34
 
12
35
  def on_module(node)
13
36
  check_code_length(node)
@@ -22,7 +45,7 @@ module RuboCop
22
45
  private
23
46
 
24
47
  def_node_matcher :module_definition?, <<~PATTERN
25
- (casgn nil? _ (block (send (const nil? :Module) :new) ...))
48
+ (casgn nil? _ (block (send (const {nil? cbase} :Module) :new) ...))
26
49
  PATTERN
27
50
 
28
51
  def message(length, max_length)
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Metrics
6
+ module Utils
7
+ # Helps to calculate code length for the provided node.
8
+ class CodeLengthCalculator
9
+ extend NodePattern::Macros
10
+ include Util
11
+
12
+ FOLDABLE_TYPES = %i[array hash heredoc].freeze
13
+ CLASSISH_TYPES = %i[class module].freeze
14
+
15
+ def initialize(node, count_comments: false, foldable_types: [])
16
+ @node = node
17
+ @count_comments = count_comments
18
+ @foldable_checks = build_foldable_checks(foldable_types)
19
+ @foldable_types = normalize_foldable_types(foldable_types)
20
+ end
21
+
22
+ def calculate
23
+ length = code_length(@node)
24
+
25
+ each_top_level_descendant(@node, *@foldable_types, *CLASSISH_TYPES) do |descendant|
26
+ descendant_length = code_length(descendant)
27
+
28
+ if classlike_node?(descendant)
29
+ length -= (descendant_length + 2)
30
+ elsif foldable_node?(descendant)
31
+ length = length - descendant_length + 1
32
+ end
33
+ end
34
+
35
+ length
36
+ end
37
+
38
+ private
39
+
40
+ def_node_matcher :class_definition?, <<~PATTERN
41
+ (casgn nil? _ (block (send (const nil? :Class) :new) ...))
42
+ PATTERN
43
+
44
+ def_node_matcher :module_definition?, <<~PATTERN
45
+ (casgn nil? _ (block (send (const nil? :Module) :new) ...))
46
+ PATTERN
47
+
48
+ def build_foldable_checks(types)
49
+ types.map do |type|
50
+ case type
51
+ when :array
52
+ ->(node) { node.array_type? }
53
+ when :hash
54
+ ->(node) { node.hash_type? }
55
+ when :heredoc
56
+ ->(node) { heredoc_node?(node) }
57
+ else
58
+ raise ArgumentError, "Unknown foldable type: #{type.inspect}. "\
59
+ "Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}."
60
+ end
61
+ end
62
+ end
63
+
64
+ def normalize_foldable_types(types)
65
+ types.concat(%i[str dstr]) if types.delete(:heredoc)
66
+ types
67
+ end
68
+
69
+ def code_length(node)
70
+ return heredoc_length(node) if heredoc_node?(node)
71
+
72
+ body = extract_body(node)
73
+ lines = body&.source&.lines || []
74
+ lines.count { |line| !irrelevant_line?(line) }
75
+ end
76
+
77
+ def heredoc_node?(node)
78
+ node.respond_to?(:heredoc?) && node.heredoc?
79
+ end
80
+
81
+ def heredoc_length(node)
82
+ lines = node.loc.heredoc_body.source.lines
83
+ lines.count { |line| !irrelevant_line?(line) } + 2
84
+ end
85
+
86
+ def each_top_level_descendant(node, *types, &block)
87
+ node.each_child_node do |child|
88
+ if types.include?(child.type)
89
+ yield child
90
+ else
91
+ each_top_level_descendant(child, *types, &block)
92
+ end
93
+ end
94
+ end
95
+
96
+ def classlike_node?(node)
97
+ CLASSISH_TYPES.include?(node.type) ||
98
+ (node.casgn_type? && (class_definition?(node) || module_definition?(node)))
99
+ end
100
+
101
+ def foldable_node?(node)
102
+ @foldable_checks.any? { |check| check.call(node) }
103
+ end
104
+
105
+ def extract_body(node)
106
+ case node.type
107
+ when :class, :module, :block, :def, :defs
108
+ node.body
109
+ when :casgn
110
+ _scope, _name, value = *node
111
+ extract_body(value)
112
+ else
113
+ node
114
+ end
115
+ end
116
+
117
+ # Returns true for lines that shall not be included in the count.
118
+ def irrelevant_line?(source_line)
119
+ source_line.blank? || !count_comments? && comment_line?(source_line)
120
+ end
121
+
122
+ def count_comments?
123
+ @count_comments
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to allow certain methods when
6
+ # parsing.
7
+ module AllowedMethods
8
+ private
9
+
10
+ def allowed_method?(name)
11
+ allowed_methods.include?(name.to_s)
12
+ end
13
+
14
+ def allowed_methods
15
+ cop_config.fetch('AllowedMethods', [])
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # extend this module to signal autocorrection support
6
+ module AutoCorrector
7
+ def support_autocorrect?
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
@@ -16,6 +16,10 @@ module RuboCop
16
16
  cop_config['CountComments']
17
17
  end
18
18
 
19
+ def count_as_one
20
+ Array(cop_config['CountAsOne']).map(&:to_sym)
21
+ end
22
+
19
23
  def check_code_length(node)
20
24
  length = code_length(node)
21
25
 
@@ -10,7 +10,7 @@ module RuboCop
10
10
  if valid_name?(node, name)
11
11
  correct_style_detected
12
12
  else
13
- add_offense(node, location: name_range, message: message(style)) do
13
+ add_offense(name_range, message: message(style)) do
14
14
  report_opposing_styles(node, name)
15
15
  end
16
16
  end
@@ -10,7 +10,9 @@ module RuboCop
10
10
  PATTERN
11
11
 
12
12
  base.def_node_matcher :class_new_definition, <<~PATTERN
13
- [!^(casgn nil? :#{base::SUPERCLASS} ...) (send (const nil? :Class) :new #{base::BASE_PATTERN})]
13
+ [!^(casgn {nil? cbase} :#{base::SUPERCLASS} ...)
14
+ !^^(casgn {nil? cbase} :#{base::SUPERCLASS} (block ...))
15
+ (send (const {nil? cbase} :Class) :new #{base::BASE_PATTERN})]
14
16
  PATTERN
15
17
  end
16
18
 
@@ -7,19 +7,17 @@ module RuboCop
7
7
  # 2. Added to NilClass by explicitly requiring any standard libraries
8
8
  # 3. Cop's configuration parameter AllowedMethods.
9
9
  module NilMethods
10
+ include AllowedMethods
11
+
10
12
  private
11
13
 
12
14
  def nil_methods
13
- nil.methods + other_stdlib_methods + allowed_methods
15
+ nil.methods + other_stdlib_methods + allowed_methods.map(&:to_sym)
14
16
  end
15
17
 
16
18
  def other_stdlib_methods
17
19
  [:to_d]
18
20
  end
19
-
20
- def allowed_methods
21
- cop_config['AllowedMethods'].map(&:to_sym)
22
- end
23
21
  end
24
22
  end
25
23
  end
@@ -15,8 +15,13 @@ module RuboCop
15
15
  node.source_range
16
16
  end
17
17
 
18
+ def gem_canonical_name(name)
19
+ name = name.tr('-_', '') unless cop_config['ConsiderPunctuation']
20
+ name.downcase
21
+ end
22
+
18
23
  def case_insensitive_out_of_order?(string_a, string_b)
19
- string_a.downcase < string_b.downcase
24
+ gem_canonical_name(string_a) < gem_canonical_name(string_b)
20
25
  end
21
26
 
22
27
  def consecutive_lines(previous, current)
@@ -14,7 +14,7 @@ module RuboCop
14
14
  private
15
15
 
16
16
  def side_space_range(range:, side:)
17
- buffer = @processed_source.buffer
17
+ buffer = processed_source.buffer
18
18
  src = buffer.source
19
19
 
20
20
  begin_pos = range.begin_pos
@@ -47,7 +47,7 @@ module RuboCop
47
47
  def token_table
48
48
  @token_table ||= begin
49
49
  table = {}
50
- @processed_source.tokens.each_with_index do |t, ix|
50
+ processed_source.tokens.each_with_index do |t, ix|
51
51
  table[t.line] ||= {}
52
52
  table[t.line][t.column] = ix
53
53
  end
@@ -55,6 +55,11 @@ module RuboCop
55
55
  end
56
56
  end
57
57
 
58
+ def on_new_investigation
59
+ @token_table = nil
60
+ super
61
+ end
62
+
58
63
  def no_space_offenses(node, # rubocop:disable Metrics/ParameterLists
59
64
  left_token,
60
65
  right_token,
@@ -16,19 +16,9 @@ module RuboCop
16
16
  end
17
17
 
18
18
  def code_length(node)
19
- body = extract_body(node)
20
- lines = body&.source&.lines || []
21
-
22
- lines.count { |line| !irrelevant_line(line) }
23
- end
24
-
25
- def extract_body(node)
26
- case node.type
27
- when :block, :def, :defs
28
- node.body
29
- else
30
- node
31
- end
19
+ Metrics::Utils::CodeLengthCalculator.new(node,
20
+ count_comments: count_comments?,
21
+ foldable_types: count_as_one).calculate
32
22
  end
33
23
  end
34
24
  end
@@ -15,11 +15,13 @@ module RuboCop
15
15
  args.each do |arg|
16
16
  # Argument names might be "_" or prefixed with "_" to indicate they
17
17
  # are unused. Trim away this prefix and only analyse the basename.
18
- full_name = arg.children.first.to_s
18
+ name_child = arg.children.first
19
+ next if name_child.nil?
20
+
21
+ full_name = name_child.to_s
19
22
  next if full_name == '_'
20
23
 
21
24
  name = full_name.gsub(/\A(_+)/, '')
22
- next if (arg.restarg_type? || arg.kwrestarg_type?) && name.empty?
23
25
  next if allowed_names.include?(name)
24
26
 
25
27
  range = arg_range(arg, name.size)
@@ -5,7 +5,9 @@
5
5
  module RuboCop
6
6
  module Cop
7
7
  module Naming
8
- # This cop checks for non-ascii characters in identifier names.
8
+ # This cop checks for non-ascii characters in identifier and constant names.
9
+ # Identifiers are always checked and whether constants are checked
10
+ # can be controlled using AsciiConstants config.
9
11
  #
10
12
  # @example
11
13
  # # bad
@@ -36,21 +38,42 @@ module RuboCop
36
38
  # # good
37
39
  # params[:width_gteq]
38
40
  #
41
+ # @example AsciiConstants: true (default)
42
+ # # bad
43
+ # class Foö
44
+ # end
45
+ #
46
+ # FOÖ = "foo"
47
+ #
48
+ # @example AsciiConstants: false
49
+ # # good
50
+ # class Foö
51
+ # end
52
+ #
53
+ # FOÖ = "foo"
54
+ #
39
55
  class AsciiIdentifiers < Cop
40
56
  include RangeHelp
41
57
 
42
- MSG = 'Use only ascii symbols in identifiers.'
58
+ IDENTIFIER_MSG = 'Use only ascii symbols in identifiers.'
59
+ CONSTANT_MSG = 'Use only ascii symbols in constants.'
43
60
 
44
61
  def investigate(processed_source)
45
62
  processed_source.each_token do |token|
46
- next unless token.type == :tIDENTIFIER && !token.text.ascii_only?
63
+ next if !should_check?(token) || token.text.ascii_only?
47
64
 
48
- add_offense(token, location: first_offense_range(token))
65
+ message = token.type == :tIDENTIFIER ? IDENTIFIER_MSG : CONSTANT_MSG
66
+ add_offense(token, location: first_offense_range(token), message: message)
49
67
  end
50
68
  end
51
69
 
52
70
  private
53
71
 
72
+ def should_check?(token)
73
+ token.type == :tIDENTIFIER ||
74
+ (token.type == :tCONSTANT && cop_config['AsciiConstants'])
75
+ end
76
+
54
77
  def first_offense_range(identifier)
55
78
  expression = identifier.pos
56
79
  first_offense = first_non_ascii_chars(identifier.text)
@@ -18,7 +18,7 @@ module RuboCop
18
18
  'name its argument `other`.'
19
19
 
20
20
  OP_LIKE_METHODS = %i[eql? equal?].freeze
21
- BLACKLISTED = %i[+@ -@ [] []= << === `].freeze
21
+ EXCLUDED = %i[+@ -@ [] []= << === `].freeze
22
22
 
23
23
  def_node_matcher :op_method_candidate?, <<~PATTERN
24
24
  (def [#op_method? $_] (args $(arg [!:other !:_other])) _)
@@ -33,7 +33,7 @@ module RuboCop
33
33
  private
34
34
 
35
35
  def op_method?(name)
36
- return false if BLACKLISTED.include?(name)
36
+ return false if EXCLUDED.include?(name)
37
37
 
38
38
  !/\A\w/.match?(name) || OP_LIKE_METHODS.include?(name)
39
39
  end
@@ -28,7 +28,7 @@ module RuboCop
28
28
  #
29
29
  # # good
30
30
  # def fooBar; end
31
- class MethodName < Cop
31
+ class MethodName < Base
32
32
  include ConfigurableNaming
33
33
  include IgnoredPattern
34
34
  include RangeHelp
@@ -49,7 +49,7 @@ module RuboCop
49
49
  def on_def(node)
50
50
  return unless node.arguments?
51
51
 
52
- check(node, node.arguments.reject(&:forward_args_type?))
52
+ check(node, node.arguments)
53
53
  end
54
54
  alias on_defs on_def
55
55
  end
@@ -28,6 +28,8 @@ module RuboCop
28
28
  # def value?
29
29
  # end
30
30
  class PredicateName < Cop
31
+ include AllowedMethods
32
+
31
33
  def_node_matcher :dynamic_method_define, <<~PATTERN
32
34
  (send nil? #method_definition_macros
33
35
  (sym $_)
@@ -70,7 +72,7 @@ module RuboCop
70
72
  !method_name.match?(/^#{prefix}[^0-9]/) ||
71
73
  method_name == expected_name(method_name, prefix) ||
72
74
  method_name.end_with?('=') ||
73
- allowed_methods.include?(method_name)
75
+ allowed_method?(method_name)
74
76
  end
75
77
 
76
78
  def expected_name(method_name, prefix)
@@ -95,10 +97,6 @@ module RuboCop
95
97
  cop_config['NamePrefix']
96
98
  end
97
99
 
98
- def allowed_methods
99
- cop_config['AllowedMethods']
100
- end
101
-
102
100
  def method_definition_macros(macro_name)
103
101
  cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
104
102
  end