rubocop 1.13.0 → 1.17.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/config/default.yml +68 -8
  4. data/lib/rubocop.rb +9 -0
  5. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -3
  6. data/lib/rubocop/cop/bundler/gem_version.rb +99 -0
  7. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  8. data/lib/rubocop/cop/layout/argument_alignment.rb +29 -11
  9. data/lib/rubocop/cop/layout/case_indentation.rb +57 -9
  10. data/lib/rubocop/cop/layout/dot_position.rb +7 -1
  11. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
  12. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +12 -0
  13. data/lib/rubocop/cop/layout/hash_alignment.rb +34 -9
  14. data/lib/rubocop/cop/layout/indentation_width.rb +13 -2
  15. data/lib/rubocop/cop/layout/redundant_line_break.rb +24 -10
  16. data/lib/rubocop/cop/layout/single_line_block_chain.rb +53 -0
  17. data/lib/rubocop/cop/layout/space_around_keyword.rb +28 -0
  18. data/lib/rubocop/cop/layout/space_around_operators.rb +6 -0
  19. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +83 -39
  20. data/lib/rubocop/cop/lint/empty_block.rb +18 -2
  21. data/lib/rubocop/cop/lint/empty_in_pattern.rb +62 -0
  22. data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
  23. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
  24. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  25. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +105 -74
  26. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
  27. data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -12
  28. data/lib/rubocop/cop/lint/unreachable_loop.rb +12 -2
  29. data/lib/rubocop/cop/lint/unused_block_argument.rb +7 -1
  30. data/lib/rubocop/cop/lint/void.rb +1 -1
  31. data/lib/rubocop/cop/migration/department_name.rb +3 -1
  32. data/lib/rubocop/cop/mixin/check_line_breakable.rb +19 -3
  33. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
  34. data/lib/rubocop/cop/mixin/gem_declaration.rb +13 -0
  35. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +14 -3
  36. data/lib/rubocop/cop/mixin/string_literals_help.rb +3 -5
  37. data/lib/rubocop/cop/mixin/symbol_help.rb +13 -0
  38. data/lib/rubocop/cop/style/class_and_module_children.rb +17 -5
  39. data/lib/rubocop/cop/style/empty_literal.rb +8 -1
  40. data/lib/rubocop/cop/style/hash_each_methods.rb +18 -1
  41. data/lib/rubocop/cop/style/identical_conditional_branches.rb +58 -8
  42. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -4
  43. data/lib/rubocop/cop/style/in_pattern_then.rb +56 -0
  44. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -1
  45. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +62 -0
  46. data/lib/rubocop/cop/style/multiline_when_then.rb +2 -11
  47. data/lib/rubocop/cop/style/negated_if_else_condition.rb +17 -9
  48. data/lib/rubocop/cop/style/nil_lambda.rb +29 -12
  49. data/lib/rubocop/cop/style/quoted_symbols.rb +110 -0
  50. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  51. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  52. data/lib/rubocop/cop/style/redundant_self.rb +24 -2
  53. data/lib/rubocop/cop/style/regexp_literal.rb +9 -1
  54. data/lib/rubocop/cop/style/single_line_methods.rb +8 -3
  55. data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
  56. data/lib/rubocop/cop/style/string_literals.rb +1 -0
  57. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -0
  58. data/lib/rubocop/cop/style/top_level_method_definition.rb +83 -0
  59. data/lib/rubocop/cop/style/trivial_accessors.rb +65 -0
  60. data/lib/rubocop/cop/style/when_then.rb +6 -2
  61. data/lib/rubocop/cop/variable_force/branch.rb +15 -0
  62. data/lib/rubocop/directive_comment.rb +58 -6
  63. data/lib/rubocop/formatter/junit_formatter.rb +21 -6
  64. data/lib/rubocop/options.rb +14 -20
  65. data/lib/rubocop/rake_task.rb +1 -1
  66. data/lib/rubocop/remote_config.rb +10 -2
  67. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  68. data/lib/rubocop/target_finder.rb +9 -2
  69. data/lib/rubocop/target_ruby.rb +1 -1
  70. data/lib/rubocop/version.rb +1 -1
  71. metadata +18 -9
@@ -35,17 +35,7 @@ module RuboCop
35
35
  MSG = 'Do not use `then` for multiline `when` statement.'
36
36
 
37
37
  def on_when(node)
38
- # Without `then`, there's no offense
39
- return unless node.then?
40
-
41
- # Single line usage of `then` is not an offense
42
- return if !node.children.last.nil? && !node.multiline?
43
-
44
- # Requires `then` for write `when` and its body on the same line.
45
- return if require_then?(node)
46
-
47
- # For arrays and hashes there's no offense
48
- return if accept_node_type?(node.body)
38
+ return if !node.then? || require_then?(node)
49
39
 
50
40
  range = node.loc.begin
51
41
  add_offense(range) do |corrector|
@@ -57,6 +47,7 @@ module RuboCop
57
47
 
58
48
  private
59
49
 
50
+ # Requires `then` for write `when` and its body on the same line.
60
51
  def require_then?(when_node)
61
52
  unless when_node.conditions.first.first_line == when_node.conditions.last.last_line
62
53
  return true
@@ -29,7 +29,6 @@ module RuboCop
29
29
  #
30
30
  class NegatedIfElseCondition < Base
31
31
  include RangeHelp
32
- include CommentsHelp
33
32
  extend AutoCorrector
34
33
 
35
34
  MSG = 'Invert the negated condition and swap the %<type>s branches.'
@@ -98,21 +97,30 @@ module RuboCop
98
97
  if node.if_branch.nil?
99
98
  corrector.remove(range_by_whole_lines(node.loc.else, include_final_newline: true))
100
99
  else
101
- if_range = node_with_comments(node.if_branch)
102
- else_range = node_with_comments(node.else_branch)
100
+ if_range = if_range(node)
101
+ else_range = else_range(node)
103
102
 
104
103
  corrector.replace(if_range, else_range.source)
105
104
  corrector.replace(else_range, if_range.source)
106
105
  end
107
106
  end
108
107
 
109
- def node_with_comments(node)
110
- first_statement = node.begin_type? ? node.children[0] : node
111
- return node if processed_source.ast_with_comments[first_statement].empty?
108
+ # Collect the entire if branch, including whitespace and comments
109
+ def if_range(node)
110
+ if node.ternary?
111
+ node.if_branch
112
+ else
113
+ range_between(node.condition.loc.expression.end_pos, node.loc.else.begin_pos)
114
+ end
115
+ end
112
116
 
113
- begin_pos = source_range_with_comment(first_statement).begin_pos
114
- end_pos = node.source_range.end_pos
115
- Parser::Source::Range.new(buffer, begin_pos, end_pos)
117
+ # Collect the entire else branch, including whitespace and comments
118
+ def else_range(node)
119
+ if node.ternary?
120
+ node.else_branch
121
+ else
122
+ range_between(node.loc.else.end_pos, node.loc.end.begin_pos)
123
+ end
116
124
  end
117
125
  end
118
126
  end
@@ -3,8 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # This cop checks for lambdas that always return nil, which can be replaced
7
- # with an empty lambda instead.
6
+ # This cop checks for lambdas and procs that always return nil,
7
+ # which can be replaced with an empty lambda or proc instead.
8
8
  #
9
9
  # @example
10
10
  # # bad
@@ -14,6 +14,12 @@ module RuboCop
14
14
  # next nil
15
15
  # end
16
16
  #
17
+ # proc { nil }
18
+ #
19
+ # Proc.new do
20
+ # break nil
21
+ # end
22
+ #
17
23
  # # good
18
24
  # -> {}
19
25
  #
@@ -22,11 +28,15 @@ module RuboCop
22
28
  #
23
29
  # -> (x) { nil if x }
24
30
  #
31
+ # proc {}
32
+ #
33
+ # Proc.new { nil if x }
34
+ #
25
35
  class NilLambda < Base
26
36
  extend AutoCorrector
27
37
  include RangeHelp
28
38
 
29
- MSG = 'Use an empty lambda instead of always returning nil.'
39
+ MSG = 'Use an empty %<type>s instead of always returning nil.'
30
40
 
31
41
  # @!method nil_return?(node)
32
42
  def_node_matcher :nil_return?, <<~PATTERN
@@ -34,19 +44,26 @@ module RuboCop
34
44
  PATTERN
35
45
 
36
46
  def on_block(node)
37
- return unless node.lambda?
47
+ return unless node.lambda? || node.proc?
38
48
  return unless nil_return?(node.body)
39
49
 
40
- add_offense(node) do |corrector|
41
- range = if node.single_line?
42
- range_with_surrounding_space(range: node.body.loc.expression)
43
- else
44
- range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
45
- end
46
-
47
- corrector.remove(range)
50
+ message = format(MSG, type: node.lambda? ? 'lambda' : 'proc')
51
+ add_offense(node, message: message) do |corrector|
52
+ autocorrect(corrector, node)
48
53
  end
49
54
  end
55
+
56
+ private
57
+
58
+ def autocorrect(corrector, node)
59
+ range = if node.single_line?
60
+ range_with_surrounding_space(range: node.body.loc.expression)
61
+ else
62
+ range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
63
+ end
64
+
65
+ corrector.remove(range)
66
+ end
50
67
  end
51
68
  end
52
69
  end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks if the quotes used for quoted symbols match the configured defaults.
7
+ # By default uses the same configuration as `Style/StringLiterals`.
8
+ #
9
+ # String interpolation is always kept in double quotes.
10
+ #
11
+ # Note: `Lint/SymbolConversion` can be used in parallel to ensure that symbols
12
+ # are not quoted that don't need to be. This cop is for configuring the quoting
13
+ # style to use for symbols that require quotes.
14
+ #
15
+ # @example EnforcedStyle: same_as_string_literals (default) / single_quotes
16
+ # # bad
17
+ # :"abc-def"
18
+ #
19
+ # # good
20
+ # :'abc-def'
21
+ # :"#{str}"
22
+ # :"a\'b"
23
+ #
24
+ # @example EnforcedStyle: double_quotes
25
+ # # bad
26
+ # :'abc-def'
27
+ #
28
+ # # good
29
+ # :"abc-def"
30
+ # :"#{str}"
31
+ # :"a\'b"
32
+ class QuotedSymbols < Base
33
+ include ConfigurableEnforcedStyle
34
+ include SymbolHelp
35
+ include StringLiteralsHelp
36
+ extend AutoCorrector
37
+
38
+ MSG_SINGLE = "Prefer single-quoted symbols when you don't need string interpolation " \
39
+ 'or special symbols.'
40
+ MSG_DOUBLE = 'Prefer double-quoted symbols unless you need single quotes to ' \
41
+ 'avoid extra backslashes for escaping.'
42
+
43
+ def on_sym(node)
44
+ return unless quoted?(node)
45
+
46
+ message = style == :single_quotes ? MSG_SINGLE : MSG_DOUBLE
47
+
48
+ if wrong_quotes?(node)
49
+ add_offense(node, message: message) do |corrector|
50
+ opposite_style_detected
51
+ autocorrect(corrector, node)
52
+ end
53
+ else
54
+ correct_style_detected
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def autocorrect(corrector, node)
61
+ str = if hash_colon_key?(node)
62
+ # strip quotes
63
+ correct_quotes(node.source[1..-2])
64
+ else
65
+ # strip leading `:` and quotes
66
+ ":#{correct_quotes(node.source[2..-2])}"
67
+ end
68
+
69
+ corrector.replace(node, str)
70
+ end
71
+
72
+ def hash_colon_key?(node)
73
+ # Is the node a hash key with the colon style?
74
+ hash_key?(node) && node.parent.colon?
75
+ end
76
+
77
+ def correct_quotes(str)
78
+ if style == :single_quotes
79
+ to_string_literal(str)
80
+ else
81
+ str.inspect
82
+ end
83
+ end
84
+
85
+ def style
86
+ return super unless super == :same_as_string_literals
87
+
88
+ string_literals_config = config.for_cop('Style/StringLiterals')
89
+ return :single_quotes unless string_literals_config['Enabled']
90
+
91
+ string_literals_config['EnforcedStyle'].to_sym
92
+ end
93
+
94
+ def alternative_style
95
+ (supported_styles - [style, :same_as_string_literals]).first
96
+ end
97
+
98
+ def quoted?(sym_node)
99
+ sym_node.source.match?(/\A:?(['"]).*?\1\z/m)
100
+ end
101
+
102
+ def wrong_quotes?(node)
103
+ return super if hash_key?(node)
104
+
105
+ super(node.source[1..-1])
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -23,6 +23,7 @@ module RuboCop
23
23
  # # good
24
24
  # raise StandardError, 'message'
25
25
  # fail 'message'
26
+ # raise MyCustomError
26
27
  # raise MyCustomError.new(arg1, arg2, arg3)
27
28
  # raise MyKwArgError.new(key1: val1, key2: val2)
28
29
  #
@@ -37,6 +38,7 @@ module RuboCop
37
38
  #
38
39
  # # good
39
40
  # raise StandardError.new('message')
41
+ # raise MyCustomError
40
42
  # raise MyCustomError.new(arg1, arg2, arg3)
41
43
  # fail 'message'
42
44
  class RaiseArgs < Base
@@ -110,7 +110,7 @@ module RuboCop
110
110
  first_child = node.children.first
111
111
 
112
112
  source = first_child.source
113
- source = "(#{source})" if first_child.if_type?
113
+ source = "(#{source})" if first_child.if_type? && first_child.modifier_form?
114
114
 
115
115
  corrector.replace(offense_range, source)
116
116
  corrector.remove(range_between(offense_range.end_pos, first_child.source_range.end_pos))
@@ -92,7 +92,7 @@ module RuboCop
92
92
 
93
93
  def on_masgn(node)
94
94
  lhs, rhs = *node
95
- lhs.children.each { |child| add_lhs_to_local_variables_scopes(rhs, child.to_a.first) }
95
+ add_masgn_lhs_variables(rhs, lhs)
96
96
  end
97
97
 
98
98
  def on_lvasgn(node)
@@ -106,7 +106,7 @@ module RuboCop
106
106
 
107
107
  return if allowed_send_node?(node)
108
108
 
109
- add_offense(node) do |corrector|
109
+ add_offense(node.receiver) do |corrector|
110
110
  corrector.remove(node.receiver)
111
111
  corrector.remove(node.loc.dot)
112
112
  end
@@ -116,6 +116,22 @@ module RuboCop
116
116
  add_scope(node, @local_variables_scopes[node])
117
117
  end
118
118
 
119
+ def on_if(node)
120
+ # Allow conditional nodes to use `self` in the condition if that variable
121
+ # name is used in an `lvasgn` or `masgn` within the `if`.
122
+ node.child_nodes.each do |child_node|
123
+ lhs, _rhs = *child_node
124
+
125
+ if child_node.lvasgn_type?
126
+ add_lhs_to_local_variables_scopes(node.condition, lhs)
127
+ elsif child_node.masgn_type?
128
+ add_masgn_lhs_variables(node.condition, lhs)
129
+ end
130
+ end
131
+ end
132
+ alias on_while on_if
133
+ alias on_until on_if
134
+
119
135
  private
120
136
 
121
137
  def add_scope(node, local_variables = [])
@@ -163,6 +179,12 @@ module RuboCop
163
179
  @local_variables_scopes[rhs] << lhs
164
180
  end
165
181
  end
182
+
183
+ def add_masgn_lhs_variables(rhs, lhs)
184
+ lhs.children.each do |child|
185
+ add_lhs_to_local_variables_scopes(rhs, child.to_a.first)
186
+ end
187
+ end
166
188
  end
167
189
  end
168
190
  end
@@ -117,7 +117,7 @@ module RuboCop
117
117
  def allowed_percent_r_literal?(node)
118
118
  style == :slashes && contains_disallowed_slash?(node) ||
119
119
  style == :percent_r ||
120
- allowed_mixed_percent_r?(node)
120
+ allowed_mixed_percent_r?(node) || omit_parentheses_style?(node)
121
121
  end
122
122
 
123
123
  def allowed_mixed_percent_r?(node)
@@ -149,6 +149,14 @@ module RuboCop
149
149
  config.for_cop('Style/PercentLiteralDelimiters') ['PreferredDelimiters']['%r'].chars
150
150
  end
151
151
 
152
+ def omit_parentheses_style?(node)
153
+ return false unless node.parent&.call_type?
154
+
155
+ enforced_style = config.for_cop('Style/MethodCallWithArgsParentheses')['EnforcedStyle']
156
+
157
+ enforced_style == 'omit_parentheses'
158
+ end
159
+
152
160
  def correct_delimiters(node, corrector)
153
161
  replacement = calculate_replacement(node)
154
162
  corrector.replace(node.loc.begin, replacement.first)
@@ -68,6 +68,7 @@ module RuboCop
68
68
  return false unless endless_method_config['Enabled']
69
69
  return false if endless_method_config['EnforcedStyle'] == 'disallow'
70
70
  return false unless body_node
71
+ return false if body_node.parent.assignment_method?
71
72
 
72
73
  !(body_node.begin_type? || body_node.kwbegin_type?)
73
74
  end
@@ -115,15 +116,19 @@ module RuboCop
115
116
  end
116
117
 
117
118
  def method_body_source(method_body)
118
- if !method_body.send_type? || method_body.arguments.empty? || method_body.parenthesized?
119
- method_body.source
120
- else
119
+ if require_parentheses?(method_body)
121
120
  arguments_source = method_body.arguments.map(&:source).join(', ')
122
121
  body_source = "#{method_body.method_name}(#{arguments_source})"
123
122
 
124
123
  method_body.receiver ? "#{method_body.receiver.source}.#{body_source}" : body_source
124
+ else
125
+ method_body.source
125
126
  end
126
127
  end
128
+
129
+ def require_parentheses?(method_body)
130
+ method_body.send_type? && !method_body.arguments.empty? && !method_body.comparison_method?
131
+ end
127
132
  end
128
133
  end
129
134
  end
@@ -80,10 +80,7 @@ module RuboCop
80
80
  def autocorrect(corrector, node, if_branch)
81
81
  corrector.wrap(node.condition, '(', ')') if node.condition.or_type?
82
82
 
83
- if node.unless?
84
- corrector.replace(node.loc.keyword, 'if')
85
- corrector.insert_before(node.condition, '!')
86
- end
83
+ correct_from_unless_to_if(corrector, node) if node.unless?
87
84
 
88
85
  and_operator = if_branch.unless? ? ' && !' : ' && '
89
86
  if if_branch.modifier_form?
@@ -94,6 +91,17 @@ module RuboCop
94
91
  end
95
92
  end
96
93
 
94
+ def correct_from_unless_to_if(corrector, node)
95
+ corrector.replace(node.loc.keyword, 'if')
96
+
97
+ condition = node.condition
98
+ if condition.send_type? && condition.comparison_method? && !condition.parenthesized?
99
+ corrector.wrap(node.condition, '!(', ')')
100
+ else
101
+ corrector.insert_before(node.condition, '!')
102
+ end
103
+ end
104
+
97
105
  def correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
98
106
  outer_condition = node.condition
99
107
  correct_outer_condition(corrector, outer_condition)
@@ -136,7 +144,8 @@ module RuboCop
136
144
  end
137
145
 
138
146
  def requrie_parentheses?(condition)
139
- condition.send_type? && !condition.arguments.empty? && !condition.parenthesized?
147
+ condition.send_type? && !condition.arguments.empty? && !condition.parenthesized? &&
148
+ !condition.comparison_method?
140
149
  end
141
150
 
142
151
  def arguments_range(node)
@@ -29,6 +29,7 @@ module RuboCop
29
29
  class StringLiterals < Base
30
30
  include ConfigurableEnforcedStyle
31
31
  include StringLiteralsHelp
32
+ include StringHelp
32
33
  extend AutoCorrector
33
34
 
34
35
  MSG_INCONSISTENT = 'Inconsistent quote style.'
@@ -22,6 +22,7 @@ module RuboCop
22
22
  class StringLiteralsInInterpolation < Base
23
23
  include ConfigurableEnforcedStyle
24
24
  include StringLiteralsHelp
25
+ include StringHelp
25
26
  extend AutoCorrector
26
27
 
27
28
  def autocorrect(corrector, node)