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
@@ -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,136 @@
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
+
37
+ GROUPED_MSG = 'Group together all `%<accessor>s` attributes.'
38
+ SEPARATED_MSG = 'Use one attribute per `%<accessor>s`.'
39
+
40
+ ACCESSOR_METHODS = %i[attr_reader attr_writer attr_accessor attr].freeze
41
+
42
+ def on_class(node)
43
+ class_send_elements(node).each do |macro|
44
+ next unless accessor?(macro)
45
+
46
+ check(macro)
47
+ end
48
+ end
49
+ alias on_module on_class
50
+
51
+ def autocorrect(node)
52
+ lambda do |corrector|
53
+ corrector.replace(node, correction(node))
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def class_send_elements(class_node)
60
+ class_def = class_node.body
61
+
62
+ if !class_def || class_def.def_type?
63
+ []
64
+ elsif class_def.send_type?
65
+ [class_def]
66
+ else
67
+ class_def.each_child_node(:send).to_a
68
+ end
69
+ end
70
+
71
+ def accessor?(send_node)
72
+ send_node.macro? && ACCESSOR_METHODS.include?(send_node.method_name)
73
+ end
74
+
75
+ def check(send_node)
76
+ if grouped_style? && sibling_accessors(send_node).size > 1
77
+ add_offense(send_node)
78
+ elsif separated_style? && send_node.arguments.size > 1
79
+ add_offense(send_node)
80
+ end
81
+ end
82
+
83
+ def grouped_style?
84
+ style == :grouped
85
+ end
86
+
87
+ def separated_style?
88
+ style == :separated
89
+ end
90
+
91
+ def sibling_accessors(send_node)
92
+ send_node.parent.each_child_node(:send).select do |sibling|
93
+ sibling.macro? && sibling.method?(send_node.method_name)
94
+ end
95
+ end
96
+
97
+ def message(send_node)
98
+ msg = grouped_style? ? GROUPED_MSG : SEPARATED_MSG
99
+ format(msg, accessor: send_node.method_name)
100
+ end
101
+
102
+ def correction(node)
103
+ if grouped_style?
104
+ accessors = sibling_accessors(node)
105
+ if node == accessors.first
106
+ group_accessors(node, accessors)
107
+ else
108
+ ''
109
+ end
110
+ else
111
+ separate_accessors(node)
112
+ end
113
+ end
114
+
115
+ def group_accessors(node, accessors)
116
+ accessor_names = accessors.flat_map do |accessor|
117
+ accessor.arguments.map(&:source)
118
+ end
119
+
120
+ "#{node.method_name} #{accessor_names.join(', ')}"
121
+ end
122
+
123
+ def separate_accessors(node)
124
+ node.arguments.map do |arg|
125
+ if arg == node.arguments.first
126
+ "#{node.method_name} #{arg.source}"
127
+ else
128
+ indent = ' ' * node.loc.column
129
+ "#{indent}#{node.method_name} #{arg.source}"
130
+ end
131
+ end.join("\n")
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,121 @@
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
+ MSG = 'Combine both accessors into `attr_accessor :%<name>s`.'
25
+
26
+ def on_class(class_node)
27
+ reader_names, writer_names = accessor_names(class_node)
28
+
29
+ accessor_macroses(class_node).each do |macro|
30
+ check(macro, reader_names, writer_names)
31
+ end
32
+ end
33
+ alias on_module on_class
34
+
35
+ def autocorrect(node)
36
+ macro = node.parent
37
+
38
+ lambda do |corrector|
39
+ corrector.replace(macro, replacement(macro, node))
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def accessor_names(class_node)
46
+ reader_names = Set.new
47
+ writer_names = Set.new
48
+
49
+ accessor_macroses(class_node).each do |macro|
50
+ names = macro.arguments.map(&:value)
51
+
52
+ names.each do |name|
53
+ if attr_reader?(macro)
54
+ reader_names.add(name)
55
+ else
56
+ writer_names.add(name)
57
+ end
58
+ end
59
+ end
60
+
61
+ [reader_names, writer_names]
62
+ end
63
+
64
+ def accessor_macroses(class_node)
65
+ class_def = class_node.body
66
+ return [] if !class_def || class_def.def_type?
67
+
68
+ send_nodes =
69
+ if class_def.send_type?
70
+ [class_def]
71
+ else
72
+ class_def.each_child_node(:send)
73
+ end
74
+
75
+ send_nodes.select { |node| node.macro? && (attr_reader?(node) || attr_writer?(node)) }
76
+ end
77
+
78
+ def attr_reader?(send_node)
79
+ send_node.method?(:attr_reader) || send_node.method?(:attr)
80
+ end
81
+
82
+ def attr_writer?(send_node)
83
+ send_node.method?(:attr_writer)
84
+ end
85
+
86
+ def check(macro, reader_names, writer_names)
87
+ macro.arguments.each do |arg_node|
88
+ name = arg_node.value
89
+
90
+ if (attr_reader?(macro) && writer_names.include?(name)) ||
91
+ (attr_writer?(macro) && reader_names.include?(name))
92
+ add_offense(arg_node, message: format(MSG, name: name))
93
+ end
94
+ end
95
+ end
96
+
97
+ def replacement(macro, node)
98
+ rest_args = macro.arguments
99
+ rest_args.delete(node)
100
+ args = rest_args.map(&:source).join(', ')
101
+
102
+ if attr_reader?(macro)
103
+ if args.empty?
104
+ "attr_accessor #{node.source}"
105
+ else
106
+ "attr_accessor #{node.source}\n#{indent(macro)}#{macro.method_name} #{args}"
107
+ end
108
+ elsif args.empty?
109
+ ''
110
+ else
111
+ "#{indent(macro)}#{macro.method_name} #{args}"
112
+ end
113
+ end
114
+
115
+ def indent(node)
116
+ ' ' * node.loc.column
117
+ end
118
+ end
119
+ end
120
+ end
121
+ 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
@@ -21,8 +21,8 @@ module RuboCop
21
21
  "file's directory."
22
22
 
23
23
  def_node_matcher :dir_replacement?, <<~PATTERN
24
- {(send (const nil? :File) :expand_path (send (const nil? :File) :dirname #file_keyword?))
25
- (send (const nil? :File) :dirname (send (const nil? :File) :realpath #file_keyword?))}
24
+ {(send (const {nil? cbase} :File) :expand_path (send (const {nil? cbase} :File) :dirname #file_keyword?))
25
+ (send (const {nil? cbase} :File) :dirname (send (const {nil? cbase} :File) :realpath #file_keyword?))}
26
26
  PATTERN
27
27
 
28
28
  def on_send(node)
@@ -25,13 +25,13 @@ module RuboCop
25
25
  STR_MSG = 'Use string literal `%<prefer>s` instead of ' \
26
26
  '`String.new`.'
27
27
 
28
- def_node_matcher :array_node, '(send (const nil? :Array) :new)'
29
- def_node_matcher :hash_node, '(send (const nil? :Hash) :new)'
30
- def_node_matcher :str_node, '(send (const nil? :String) :new)'
28
+ def_node_matcher :array_node, '(send (const {nil? cbase} :Array) :new)'
29
+ def_node_matcher :hash_node, '(send (const {nil? cbase} :Hash) :new)'
30
+ def_node_matcher :str_node, '(send (const {nil? cbase} :String) :new)'
31
31
  def_node_matcher :array_with_block,
32
- '(block (send (const nil? :Array) :new) args _)'
32
+ '(block (send (const {nil? cbase} :Array) :new) args _)'
33
33
  def_node_matcher :hash_with_block,
34
- '(block (send (const nil? :Hash) :new) args _)'
34
+ '(block (send (const {nil? cbase} :Hash) :new) args _)'
35
35
 
36
36
  def on_send(node)
37
37
  add_offense(node, message: ARR_MSG) if offense_array_node?(node)
@@ -53,7 +53,7 @@ module RuboCop
53
53
 
54
54
  def_node_matcher :file_expand_path, <<~PATTERN
55
55
  (send
56
- (const nil? :File) :expand_path
56
+ (const {nil? cbase} :File) :expand_path
57
57
  $_
58
58
  $_)
59
59
  PATTERN
@@ -69,7 +69,7 @@ module RuboCop
69
69
  (send
70
70
  (send
71
71
  (send
72
- (const nil? :Pathname) :new
72
+ (const {nil? cbase} :Pathname) :new
73
73
  $_) :parent) :expand_path)
74
74
  PATTERN
75
75
 
@@ -33,6 +33,18 @@ module RuboCop
33
33
  add_offense(node, location: :keyword,
34
34
  message: format(MSG, keyword: node.keyword))
35
35
  end
36
+
37
+ def autocorrect(node)
38
+ lambda do |corrector|
39
+ keyword = node.if? ? 'if' : 'unless'
40
+
41
+ corrector.replace(node, <<~RUBY.chop)
42
+ #{keyword} #{node.condition.source}
43
+ #{node.if_branch.source}
44
+ end
45
+ RUBY
46
+ end
47
+ end
36
48
  end
37
49
  end
38
50
  end
@@ -8,11 +8,20 @@ module RuboCop
8
8
  #
9
9
  # @example
10
10
  #
11
- # Thread.list.find_all do |t|
11
+ # # bad
12
+ # Thread.list.select do |t|
12
13
  # t.alive?
13
14
  # end.map do |t|
14
15
  # t.object_id
15
16
  # end
17
+ #
18
+ # # good
19
+ # alive_threads = Thread.list.select do |t|
20
+ # t.alive?
21
+ # end
22
+ # alive_threads.map do |t|
23
+ # t.object_id
24
+ # end
16
25
  class MultilineBlockChain < Cop
17
26
  include RangeHelp
18
27