rubocop 0.86.0 → 0.87.1

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 (104) 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 +8 -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 +21 -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/class_structure.rb +2 -37
  21. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -8
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -0
  23. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -2
  24. data/lib/rubocop/cop/layout/multiline_block_layout.rb +0 -1
  25. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +19 -25
  26. data/lib/rubocop/cop/legacy/corrections_proxy.rb +49 -0
  27. data/lib/rubocop/cop/legacy/corrector.rb +29 -0
  28. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -4
  29. data/lib/rubocop/cop/lint/interpolation_check.rb +13 -0
  30. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  31. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
  32. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -3
  33. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  34. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -23
  35. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +2 -2
  36. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +8 -0
  37. data/lib/rubocop/cop/lint/syntax.rb +11 -26
  38. data/lib/rubocop/cop/lint/unused_method_argument.rb +1 -1
  39. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  40. data/lib/rubocop/cop/metrics/block_length.rb +22 -0
  41. data/lib/rubocop/cop/metrics/class_length.rb +25 -2
  42. data/lib/rubocop/cop/metrics/method_length.rb +23 -0
  43. data/lib/rubocop/cop/metrics/module_length.rb +25 -2
  44. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +129 -0
  45. data/lib/rubocop/cop/mixin/allowed_methods.rb +19 -0
  46. data/lib/rubocop/cop/mixin/auto_corrector.rb +12 -0
  47. data/lib/rubocop/cop/mixin/code_length.rb +4 -0
  48. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
  49. data/lib/rubocop/cop/mixin/enforce_superclass.rb +3 -1
  50. data/lib/rubocop/cop/mixin/nil_methods.rb +3 -5
  51. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +6 -1
  52. data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -2
  53. data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -13
  54. data/lib/rubocop/cop/mixin/uncommunicative_name.rb +4 -2
  55. data/lib/rubocop/cop/mixin/visibility_help.rb +50 -0
  56. data/lib/rubocop/cop/naming/ascii_identifiers.rb +27 -4
  57. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +2 -2
  58. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  59. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  60. data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
  61. data/lib/rubocop/cop/naming/variable_name.rb +1 -1
  62. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  63. data/lib/rubocop/cop/offense.rb +16 -2
  64. data/lib/rubocop/cop/style/accessor_grouping.rb +140 -0
  65. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +145 -0
  66. data/lib/rubocop/cop/style/class_vars.rb +21 -0
  67. data/lib/rubocop/cop/style/date_time.rb +1 -1
  68. data/lib/rubocop/cop/style/dir.rb +2 -2
  69. data/lib/rubocop/cop/style/empty_literal.rb +5 -5
  70. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
  71. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -0
  72. data/lib/rubocop/cop/style/multiline_block_chain.rb +10 -1
  73. data/lib/rubocop/cop/style/mutable_constant.rb +4 -4
  74. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -5
  75. data/lib/rubocop/cop/style/proc.rb +1 -1
  76. data/lib/rubocop/cop/style/random_with_offset.rb +4 -10
  77. data/lib/rubocop/cop/style/redundant_assignment.rb +117 -0
  78. data/lib/rubocop/cop/style/redundant_exception.rb +14 -10
  79. data/lib/rubocop/cop/style/redundant_fetch_block.rb +26 -7
  80. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  81. data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
  82. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -1
  83. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -2
  84. data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -1
  85. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  86. data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
  87. data/lib/rubocop/cop/style/struct_inheritance.rb +2 -2
  88. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  89. data/lib/rubocop/cop/style/trivial_accessors.rb +8 -7
  90. data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -2
  91. data/lib/rubocop/cop/team.rb +97 -81
  92. data/lib/rubocop/cop/utils/format_string.rb +1 -2
  93. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  94. data/lib/rubocop/name_similarity.rb +1 -3
  95. data/lib/rubocop/options.rb +15 -8
  96. data/lib/rubocop/rake_task.rb +6 -9
  97. data/lib/rubocop/rspec/cop_helper.rb +4 -4
  98. data/lib/rubocop/rspec/expect_offense.rb +22 -17
  99. data/lib/rubocop/rspec/shared_contexts.rb +7 -7
  100. data/lib/rubocop/runner.rb +31 -29
  101. data/lib/rubocop/target_ruby.rb +1 -1
  102. data/lib/rubocop/version.rb +1 -1
  103. metadata +16 -7
  104. data/lib/rubocop/cop/mixin/classish_length.rb +0 -37
@@ -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
@@ -19,7 +19,7 @@ module RuboCop
19
19
  #
20
20
  # # good
21
21
  # fooBar = 1
22
- class VariableName < Cop
22
+ class VariableName < Base
23
23
  include ConfigurableNaming
24
24
 
25
25
  MSG = 'Use %<style>s for variable names.'
@@ -37,7 +37,7 @@ module RuboCop
37
37
  # variableone = 1
38
38
  #
39
39
  # variable_one = 1
40
- class VariableNumber < Cop
40
+ class VariableNumber < Base
41
41
  include ConfigurableNumbering
42
42
 
43
43
  MSG = 'Use %<style>s for variable numbers.'
@@ -54,14 +54,28 @@ module RuboCop
54
54
  # @api private
55
55
  attr_reader :status
56
56
 
57
+ # @api public
58
+ #
59
+ # @!attribute [r] corrector
60
+ #
61
+ # @return [Corrector | nil]
62
+ # the autocorrection for this offense, or `nil` when not available
63
+ attr_reader :corrector
64
+
65
+ PseudoSourceRange = Struct.new(:line, :column, :source_line, :begin_pos,
66
+ :end_pos)
67
+
68
+ NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0, 1).freeze
69
+
57
70
  # @api private
58
- def initialize(severity, location, message, cop_name,
59
- status = :uncorrected)
71
+ def initialize(severity, location, message, cop_name, # rubocop:disable Metrics/ParameterLists
72
+ status = :uncorrected, corrector = nil)
60
73
  @severity = RuboCop::Cop::Severity.new(severity)
61
74
  @location = location
62
75
  @message = message.freeze
63
76
  @cop_name = cop_name.freeze
64
77
  @status = status
78
+ @corrector = corrector
65
79
  freeze
66
80
  end
67
81
 
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for grouping of accessors in `class` and `module` bodies.
7
+ # By default it enforces accessors to be placed in grouped declarations,
8
+ # but it can be configured to enforce separating them in multiple declarations.
9
+ #
10
+ # @example EnforcedStyle: grouped (default)
11
+ # # bad
12
+ # class Foo
13
+ # attr_reader :bar
14
+ # attr_reader :baz
15
+ # end
16
+ #
17
+ # # good
18
+ # class Foo
19
+ # attr_reader :bar, :baz
20
+ # end
21
+ #
22
+ # @example EnforcedStyle: separated
23
+ # # bad
24
+ # class Foo
25
+ # attr_reader :bar, :baz
26
+ # end
27
+ #
28
+ # # good
29
+ # class Foo
30
+ # attr_reader :bar
31
+ # attr_reader :baz
32
+ # end
33
+ #
34
+ class AccessorGrouping < Cop
35
+ include ConfigurableEnforcedStyle
36
+ include VisibilityHelp
37
+
38
+ GROUPED_MSG = 'Group together all `%<accessor>s` attributes.'
39
+ SEPARATED_MSG = 'Use one attribute per `%<accessor>s`.'
40
+
41
+ ACCESSOR_METHODS = %i[attr_reader attr_writer attr_accessor attr].freeze
42
+
43
+ def on_class(node)
44
+ class_send_elements(node).each do |macro|
45
+ next unless accessor?(macro)
46
+
47
+ check(macro)
48
+ end
49
+ end
50
+ alias on_sclass on_class
51
+ alias on_module on_class
52
+
53
+ def autocorrect(node)
54
+ lambda do |corrector|
55
+ corrector.replace(node, correction(node))
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def class_send_elements(class_node)
62
+ class_def = class_node.body
63
+
64
+ if !class_def || class_def.def_type?
65
+ []
66
+ elsif class_def.send_type?
67
+ [class_def]
68
+ else
69
+ class_def.each_child_node(:send).to_a
70
+ end
71
+ end
72
+
73
+ def accessor?(send_node)
74
+ send_node.macro? && ACCESSOR_METHODS.include?(send_node.method_name)
75
+ end
76
+
77
+ def check(send_node)
78
+ if grouped_style? && sibling_accessors(send_node).size > 1
79
+ add_offense(send_node)
80
+ elsif separated_style? && send_node.arguments.size > 1
81
+ add_offense(send_node)
82
+ end
83
+ end
84
+
85
+ def grouped_style?
86
+ style == :grouped
87
+ end
88
+
89
+ def separated_style?
90
+ style == :separated
91
+ end
92
+
93
+ def sibling_accessors(send_node)
94
+ send_node.parent.each_child_node(:send).select do |sibling|
95
+ accessor?(sibling) &&
96
+ sibling.method?(send_node.method_name) &&
97
+ node_visibility(sibling) == node_visibility(send_node)
98
+ end
99
+ end
100
+
101
+ def message(send_node)
102
+ msg = grouped_style? ? GROUPED_MSG : SEPARATED_MSG
103
+ format(msg, accessor: send_node.method_name)
104
+ end
105
+
106
+ def correction(node)
107
+ if grouped_style?
108
+ accessors = sibling_accessors(node)
109
+ if node == accessors.first
110
+ group_accessors(node, accessors)
111
+ else
112
+ ''
113
+ end
114
+ else
115
+ separate_accessors(node)
116
+ end
117
+ end
118
+
119
+ def group_accessors(node, accessors)
120
+ accessor_names = accessors.flat_map do |accessor|
121
+ accessor.arguments.map(&:source)
122
+ end
123
+
124
+ "#{node.method_name} #{accessor_names.join(', ')}"
125
+ end
126
+
127
+ def separate_accessors(node)
128
+ node.arguments.map do |arg|
129
+ if arg == node.arguments.first
130
+ "#{node.method_name} #{arg.source}"
131
+ else
132
+ indent = ' ' * node.loc.column
133
+ "#{indent}#{node.method_name} #{arg.source}"
134
+ end
135
+ end.join("\n")
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Style
8
+ # This cop checks for places where `attr_reader` and `attr_writer`
9
+ # for the same method can be combined into single `attr_accessor`.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # class Foo
14
+ # attr_reader :bar
15
+ # attr_writer :bar
16
+ # end
17
+ #
18
+ # # good
19
+ # class Foo
20
+ # attr_accessor :bar
21
+ # end
22
+ #
23
+ class BisectedAttrAccessor < Cop
24
+ include VisibilityHelp
25
+
26
+ MSG = 'Combine both accessors into `attr_accessor %<name>s`.'
27
+
28
+ def on_class(class_node)
29
+ VISIBILITY_SCOPES.each do |visibility|
30
+ reader_names, writer_names = accessor_names(class_node, visibility)
31
+
32
+ accessor_macroses(class_node, visibility).each do |macro|
33
+ check(macro, reader_names, writer_names)
34
+ end
35
+ end
36
+ end
37
+ alias on_sclass on_class
38
+ alias on_module on_class
39
+
40
+ def autocorrect(node)
41
+ macro = node.parent
42
+
43
+ lambda do |corrector|
44
+ corrector.replace(macro, replacement(macro, node))
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def accessor_names(class_node, visibility)
51
+ reader_names = Set.new
52
+ writer_names = Set.new
53
+
54
+ accessor_macroses(class_node, visibility).each do |macro|
55
+ names = macro.arguments.map(&:source)
56
+
57
+ names.each do |name|
58
+ if attr_reader?(macro)
59
+ reader_names.add(name)
60
+ else
61
+ writer_names.add(name)
62
+ end
63
+ end
64
+ end
65
+
66
+ [reader_names, writer_names]
67
+ end
68
+
69
+ def accessor_macroses(class_node, visibility)
70
+ class_def = class_node.body
71
+ return [] if !class_def || class_def.def_type?
72
+
73
+ send_nodes =
74
+ if class_def.send_type?
75
+ [class_def]
76
+ else
77
+ class_def.each_child_node(:send)
78
+ end
79
+
80
+ send_nodes.select { |node| attr_within_visibility_scope?(node, visibility) }
81
+ end
82
+
83
+ def attr_within_visibility_scope?(node, visibility)
84
+ node.macro? &&
85
+ (attr_reader?(node) || attr_writer?(node)) &&
86
+ node_visibility(node) == visibility
87
+ end
88
+
89
+ def attr_reader?(send_node)
90
+ send_node.method?(:attr_reader) || send_node.method?(:attr)
91
+ end
92
+
93
+ def attr_writer?(send_node)
94
+ send_node.method?(:attr_writer)
95
+ end
96
+
97
+ def check(macro, reader_names, writer_names)
98
+ macro.arguments.each do |arg_node|
99
+ name = arg_node.source
100
+
101
+ if (attr_reader?(macro) && writer_names.include?(name)) ||
102
+ (attr_writer?(macro) && reader_names.include?(name))
103
+ add_offense(arg_node, message: format(MSG, name: name))
104
+ end
105
+ end
106
+ end
107
+
108
+ def replacement(macro, node)
109
+ class_node = macro.each_ancestor(:class, :sclass, :module).first
110
+ reader_names, writer_names = accessor_names(class_node, node_visibility(macro))
111
+
112
+ rest_args = rest_args(macro.arguments, reader_names, writer_names)
113
+
114
+ if attr_reader?(macro)
115
+ attr_reader_replacement(macro, node, rest_args)
116
+ elsif rest_args.empty?
117
+ ''
118
+ else
119
+ "#{macro.method_name} #{rest_args.map(&:source).join(', ')}"
120
+ end
121
+ end
122
+
123
+ def rest_args(args, reader_names, writer_names)
124
+ args.reject do |arg|
125
+ name = arg.source
126
+ reader_names.include?(name) && writer_names.include?(name)
127
+ end
128
+ end
129
+
130
+ def attr_reader_replacement(macro, node, rest_args)
131
+ if rest_args.empty?
132
+ "attr_accessor #{node.source}"
133
+ else
134
+ "attr_accessor #{node.source}\n"\
135
+ "#{indent(macro)}#{macro.method_name} #{rest_args.map(&:source).join(', ')}"
136
+ end
137
+ end
138
+
139
+ def indent(node)
140
+ ' ' * node.loc.column
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -19,6 +19,15 @@ module RuboCop
19
19
  # @@test = 10
20
20
  # end
21
21
  #
22
+ # class A
23
+ # def self.test(name, value)
24
+ # class_variable_set("@@#{name}", value)
25
+ # end
26
+ # end
27
+ #
28
+ # class A; end
29
+ # A.class_variable_set(:@@test, 10)
30
+ #
22
31
  # # good
23
32
  # class A
24
33
  # @test = 10
@@ -30,6 +39,12 @@ module RuboCop
30
39
  # end
31
40
  # end
32
41
  #
42
+ # class A
43
+ # def self.test(name)
44
+ # class_variable_get("@@#{name}") # you can access without offense
45
+ # end
46
+ # end
47
+ #
33
48
  class ClassVars < Cop
34
49
  MSG = 'Replace class var %<class_var>s with a class ' \
35
50
  'instance var.'
@@ -38,6 +53,12 @@ module RuboCop
38
53
  add_offense(node, location: :name)
39
54
  end
40
55
 
56
+ def on_send(node)
57
+ return unless node.method?(:class_variable_set)
58
+
59
+ add_offense(node.first_argument)
60
+ end
61
+
41
62
  def message(node)
42
63
  class_var, = *node
43
64
  format(MSG, class_var: class_var)
@@ -50,7 +50,7 @@ module RuboCop
50
50
  PATTERN
51
51
 
52
52
  def_node_matcher :historic_date?, <<~PATTERN
53
- (send _ _ _ (const (const nil? :Date) _))
53
+ (send _ _ _ (const (const {nil? (cbase)} :Date) _))
54
54
  PATTERN
55
55
 
56
56
  def_node_matcher :to_datetime?, <<~PATTERN