rubocop 0.40.0 → 0.41.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -1014
  3. data/config/default.yml +61 -5
  4. data/config/disabled.yml +6 -0
  5. data/config/enabled.yml +63 -4
  6. data/lib/rubocop.rb +17 -1
  7. data/lib/rubocop/ast_node.rb +56 -42
  8. data/lib/rubocop/ast_node/traversal.rb +3 -3
  9. data/lib/rubocop/cli.rb +14 -9
  10. data/lib/rubocop/comment_config.rb +85 -32
  11. data/lib/rubocop/config.rb +29 -8
  12. data/lib/rubocop/config_loader.rb +1 -1
  13. data/lib/rubocop/cop/cop.rb +1 -1
  14. data/lib/rubocop/cop/corrector.rb +13 -0
  15. data/lib/rubocop/cop/lint/block_alignment.rb +25 -11
  16. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +5 -2
  17. data/lib/rubocop/cop/lint/inherit_exception.rb +69 -0
  18. data/lib/rubocop/cop/lint/percent_string_array.rb +60 -0
  19. data/lib/rubocop/cop/lint/percent_symbol_array.rb +57 -0
  20. data/lib/rubocop/cop/lint/shadowed_exception.rb +95 -0
  21. data/lib/rubocop/cop/lint/useless_access_modifier.rb +28 -13
  22. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +25 -19
  23. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +16 -8
  24. data/lib/rubocop/cop/mixin/if_node.rb +1 -2
  25. data/lib/rubocop/cop/mixin/integer_node.rb +13 -0
  26. data/lib/rubocop/cop/mixin/match_range.rb +26 -0
  27. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +16 -7
  28. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +18 -1
  29. data/lib/rubocop/cop/mixin/negative_conditional.rb +6 -4
  30. data/lib/rubocop/cop/mixin/percent_literal.rb +10 -0
  31. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +24 -6
  32. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +20 -7
  33. data/lib/rubocop/cop/mixin/string_literals_help.rb +2 -2
  34. data/lib/rubocop/cop/mixin/trailing_comma.rb +34 -20
  35. data/lib/rubocop/cop/performance/flat_map.rb +23 -10
  36. data/lib/rubocop/cop/performance/push_splat.rb +47 -0
  37. data/lib/rubocop/cop/performance/redundant_block_call.rb +24 -1
  38. data/lib/rubocop/cop/performance/redundant_merge.rb +3 -5
  39. data/lib/rubocop/cop/performance/sample.rb +15 -11
  40. data/lib/rubocop/cop/rails/exit.rb +62 -0
  41. data/lib/rubocop/cop/rails/output_safety.rb +45 -0
  42. data/lib/rubocop/cop/rails/pluralization_grammar.rb +12 -4
  43. data/lib/rubocop/cop/rails/request_referer.rb +40 -0
  44. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +63 -28
  45. data/lib/rubocop/cop/rails/validation.rb +37 -23
  46. data/lib/rubocop/cop/style/alias.rb +10 -6
  47. data/lib/rubocop/cop/style/bare_percent_literals.rb +18 -7
  48. data/lib/rubocop/cop/style/block_delimiters.rb +15 -22
  49. data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +19 -8
  50. data/lib/rubocop/cop/style/comment_indentation.rb +13 -5
  51. data/lib/rubocop/cop/style/conditional_assignment.rb +111 -59
  52. data/lib/rubocop/cop/style/documentation.rb +7 -1
  53. data/lib/rubocop/cop/style/each_for_simple_loop.rb +43 -0
  54. data/lib/rubocop/cop/style/each_with_object.rb +25 -14
  55. data/lib/rubocop/cop/style/empty_else.rb +6 -10
  56. data/lib/rubocop/cop/style/extra_spacing.rb +20 -3
  57. data/lib/rubocop/cop/style/file_name.rb +16 -4
  58. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  59. data/lib/rubocop/cop/style/hash_syntax.rb +9 -2
  60. data/lib/rubocop/cop/style/if_unless_modifier.rb +20 -13
  61. data/lib/rubocop/cop/style/implicit_runtime_error.rb +32 -0
  62. data/lib/rubocop/cop/style/infinite_loop.rb +42 -5
  63. data/lib/rubocop/cop/style/lambda.rb +22 -0
  64. data/lib/rubocop/cop/style/method_def_parentheses.rb +12 -4
  65. data/lib/rubocop/cop/style/module_function.rb +28 -6
  66. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +49 -12
  67. data/lib/rubocop/cop/style/mutable_constant.rb +8 -1
  68. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  69. data/lib/rubocop/cop/style/next.rb +43 -31
  70. data/lib/rubocop/cop/style/not.rb +33 -13
  71. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +92 -0
  72. data/lib/rubocop/cop/style/numeric_literals.rb +1 -4
  73. data/lib/rubocop/cop/style/parallel_assignment.rb +26 -8
  74. data/lib/rubocop/cop/style/{deprecated_hash_methods.rb → preferred_hash_methods.rb} +8 -8
  75. data/lib/rubocop/cop/style/redundant_parentheses.rb +29 -19
  76. data/lib/rubocop/cop/style/redundant_self.rb +13 -6
  77. data/lib/rubocop/cop/style/space_after_not.rb +7 -5
  78. data/lib/rubocop/cop/style/space_around_keyword.rb +6 -0
  79. data/lib/rubocop/cop/style/space_around_operators.rb +5 -1
  80. data/lib/rubocop/cop/style/space_before_first_arg.rb +21 -9
  81. data/lib/rubocop/cop/style/space_inside_array_percent_literal.rb +53 -0
  82. data/lib/rubocop/cop/style/space_inside_block_braces.rb +2 -2
  83. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +26 -6
  84. data/lib/rubocop/cop/style/space_inside_percent_literal_delimiters.rb +64 -0
  85. data/lib/rubocop/cop/style/string_literals.rb +37 -8
  86. data/lib/rubocop/cop/style/symbol_array.rb +21 -12
  87. data/lib/rubocop/cop/style/symbol_proc.rb +26 -19
  88. data/lib/rubocop/cop/style/word_array.rb +1 -5
  89. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -6
  90. data/lib/rubocop/cop/team.rb +40 -27
  91. data/lib/rubocop/cop/util.rb +13 -42
  92. data/lib/rubocop/formatter/disabled_config_formatter.rb +37 -14
  93. data/lib/rubocop/formatter/html_formatter.rb +3 -7
  94. data/lib/rubocop/result_cache.rb +18 -4
  95. data/{spec/support → lib/rubocop/rspec}/cop_helper.rb +3 -0
  96. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +33 -0
  97. data/lib/rubocop/rspec/shared_contexts.rb +75 -0
  98. data/lib/rubocop/rspec/shared_examples.rb +101 -0
  99. data/lib/rubocop/rspec/support.rb +9 -0
  100. data/lib/rubocop/runner.rb +2 -2
  101. data/lib/rubocop/string_interpreter.rb +58 -0
  102. data/lib/rubocop/version.rb +1 -1
  103. metadata +27 -7
@@ -30,7 +30,14 @@ module RuboCop
30
30
 
31
31
  def autocorrect(node)
32
32
  expr = node.source_range
33
- ->(corrector) { corrector.replace(expr, "#{expr.source}.freeze") }
33
+ lambda do |corrector|
34
+ if node.array_type? && node.loc.begin.nil? && node.loc.end.nil?
35
+ corrector.insert_before(expr, '[')
36
+ corrector.insert_after(expr, '].freeze')
37
+ else
38
+ corrector.insert_after(expr, '.freeze')
39
+ end
40
+ end
34
41
  end
35
42
 
36
43
  private
@@ -51,7 +51,7 @@ module RuboCop
51
51
  def modifier_while_or_until?(node)
52
52
  node.loc.respond_to?(:keyword) &&
53
53
  %w(while until).include?(node.loc.keyword.source) &&
54
- node.loc.respond_to?(:end) && node.loc.end.nil?
54
+ node.modifier_form?
55
55
  end
56
56
 
57
57
  def autocorrect(node)
@@ -81,18 +81,22 @@ module RuboCop
81
81
  end
82
82
 
83
83
  def simple_if_without_break?(node)
84
- return false unless node.if_type?
85
- return false if ternary?(node)
86
- return false if if_else?(node)
84
+ return false unless if_without_else?(node)
87
85
  return false if style == :skip_modifier_ifs && modifier_if?(node)
88
86
  return false if !modifier_if?(node) && !min_body_length?(node)
89
87
 
90
- # The `if` node must have only `if` body since we excluded `if` with
91
- # `else` above.
88
+ !exit_body_type?(node)
89
+ end
90
+
91
+ def if_without_else?(node)
92
+ node.if_type? && !ternary?(node) && !if_else?(node)
93
+ end
94
+
95
+ def exit_body_type?(node)
92
96
  _conditional, if_body, _else_body = *node
93
- return true unless if_body
97
+ return false unless if_body
94
98
 
95
- !EXIT_TYPES.include?(if_body.type)
99
+ EXIT_TYPES.include?(if_body.type)
96
100
  end
97
101
 
98
102
  def offense_node(body)
@@ -135,10 +139,10 @@ module RuboCop
135
139
  corrector.remove(cond_range(node, cond))
136
140
  corrector.remove(end_range(node))
137
141
 
138
- # end_range starts with the final newline of the if body
139
- reindent_lines = (node.source_range.line + 1)...node.loc.end.line
140
- reindent_lines = reindent_lines.to_a - heredoc_lines(node)
141
- reindent(reindent_lines, cond, corrector)
142
+ lines = reindentable_lines(node)
143
+ return if lines.empty?
144
+
145
+ reindent(lines, cond, corrector)
142
146
  end
143
147
 
144
148
  def opposite_kw(if_body)
@@ -170,42 +174,50 @@ module RuboCop
170
174
  source_buffer.source[end_pos..-1] =~ /\A\s*$/
171
175
  end
172
176
 
177
+ def reindentable_lines(node)
178
+ buffer = node.source_range.source_buffer
179
+
180
+ # end_range starts with the final newline of the if body
181
+ lines = (node.source_range.line + 1)...node.loc.end.line
182
+ lines = lines.to_a - heredoc_lines(node)
183
+ # Skip blank lines
184
+ lines.reject { |lineno| buffer.source_line(lineno) =~ /\A\s*\z/ }
185
+ end
186
+
173
187
  # Adjust indentation of `lines` to match `node`
174
188
  def reindent(lines, node, corrector)
175
189
  range = node.source_range
176
190
  buffer = range.source_buffer
177
191
 
178
192
  target_indent = range.source_line =~ /\S/
179
-
180
- # Skip blank lines
181
- lines.reject! { |lineno| buffer.source_line(lineno) =~ /\A\s*\z/ }
182
- return if lines.empty?
183
-
184
- actual_indent = lines.map do |lineno|
185
- buffer.source_line(lineno) =~ /\S/
186
- end.min
187
-
188
- delta = actual_indent - target_indent
193
+ delta = actual_indent(lines, buffer) - target_indent
189
194
  lines.each do |lineno|
190
- adjustment = delta
191
- adjustment += @reindented_lines[lineno]
192
- @reindented_lines[lineno] = adjustment
193
-
194
- if adjustment > 0
195
- corrector.remove_leading(buffer.line_range(lineno), adjustment)
196
- elsif adjustment < 0
197
- corrector.insert_before(buffer.line_range(lineno),
198
- ' ' * -adjustment)
199
- end
195
+ reindent_line(corrector, lineno, delta, buffer)
200
196
  end
201
197
  end
202
198
 
199
+ def actual_indent(lines, buffer)
200
+ lines.map { |lineno| buffer.source_line(lineno) =~ /\S/ }.min
201
+ end
202
+
203
203
  def heredoc_lines(node)
204
204
  node.each_node(:dstr)
205
205
  .select { |n| n.loc.respond_to?(:heredoc_body) }
206
206
  .map { |n| n.loc.heredoc_body }
207
207
  .flat_map { |b| (b.line...b.last_line).to_a }
208
208
  end
209
+
210
+ def reindent_line(corrector, lineno, delta, buffer)
211
+ adjustment = delta + @reindented_lines[lineno]
212
+ @reindented_lines[lineno] = adjustment
213
+
214
+ if adjustment > 0
215
+ corrector.remove_leading(buffer.line_range(lineno), adjustment)
216
+ elsif adjustment < 0
217
+ corrector.insert_before(buffer.line_range(lineno),
218
+ ' ' * -adjustment)
219
+ end
220
+ end
209
221
  end
210
222
  end
211
223
  end
@@ -31,22 +31,42 @@ module RuboCop
31
31
  range = range_with_surrounding_space(node.loc.selector, :right)
32
32
  child = node.children.first
33
33
 
34
- if child.send_type? && OPPOSITE_METHODS.key?(child.method_name)
35
- lambda do |corrector|
36
- corrector.remove(range)
37
- corrector.replace(child.loc.selector,
38
- OPPOSITE_METHODS[child.method_name].to_s)
39
- end
40
- elsif child.and_type? || child.or_type? || child.binary_operation? ||
41
- ternary?(child)
42
- lambda do |corrector|
43
- corrector.replace(range, '!(')
44
- corrector.insert_after(node.source_range, ')')
45
- end
34
+ if opposite_method?(child)
35
+ correct_opposite_method(range, child)
36
+ elsif requires_parens?(child)
37
+ correct_with_parens(range, node)
46
38
  else
47
- ->(corrector) { corrector.replace(range, '!') }
39
+ correct_without_parens(range)
48
40
  end
49
41
  end
42
+
43
+ def opposite_method?(child)
44
+ child.send_type? && OPPOSITE_METHODS.key?(child.method_name)
45
+ end
46
+
47
+ def requires_parens?(child)
48
+ child.and_type? || child.or_type? || child.binary_operation? ||
49
+ ternary?(child)
50
+ end
51
+
52
+ def correct_opposite_method(range, child)
53
+ lambda do |corrector|
54
+ corrector.remove(range)
55
+ corrector.replace(child.loc.selector,
56
+ OPPOSITE_METHODS[child.method_name].to_s)
57
+ end
58
+ end
59
+
60
+ def correct_with_parens(range, node)
61
+ lambda do |corrector|
62
+ corrector.replace(range, '!(')
63
+ corrector.insert_after(node.source_range, ')')
64
+ end
65
+ end
66
+
67
+ def correct_without_parens(range)
68
+ ->(corrector) { corrector.replace(range, '!') }
69
+ end
50
70
  end
51
71
  end
52
72
  end
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Style
7
+ # This cop checks for octal, hex, binary and decimal literals using
8
+ # uppercase prefixes and corrects them to lowercase prefix
9
+ # or no prefix (in case of decimals).
10
+ # eg. for octal use `0o` instead of `0` or `0O`.
11
+ #
12
+ # Can be configured to use `0` only for octal literals using
13
+ # `EnforcedOctalStyle` => `zero_only`
14
+ class NumericLiteralPrefix < Cop
15
+ include IntegerNode
16
+
17
+ OCTAL_ZERO_ONLY_REGEX = /^0[Oo][0-7]+$/
18
+ OCTAL_REGEX = /^0O?[0-7]+$/
19
+ HEX_REGEX = /^0X[0-9A-F]+$/
20
+ BINARY_REGEX = /^0B[01]+$/
21
+ DECIMAL_REGEX = /^0[dD][0-9]+$/
22
+
23
+ OCTAL_ZERO_ONLY_MSG = 'Use 0 for octal literals.'.freeze
24
+ OCTAL_MSG = 'Use 0o for octal literals.'.freeze
25
+ HEX_MSG = 'Use 0x for hexadecimal literals.'.freeze
26
+ BINARY_MSG = 'Use 0b for binary literals.'.freeze
27
+ DECIMAL_MSG = 'Do not use prefixes for decimal literals.'.freeze
28
+
29
+ def on_int(node)
30
+ type = literal_type(node)
31
+ return unless type
32
+
33
+ msg = self.class.const_get("#{type.upcase}_MSG")
34
+ add_offense(node, :expression, msg)
35
+ end
36
+
37
+ private
38
+
39
+ def autocorrect(node)
40
+ lambda do |corrector|
41
+ type = literal_type(node)
42
+ corrector.replace(node.source_range,
43
+ send(:"format_#{type}", node.source))
44
+ end
45
+ end
46
+
47
+ def literal_type(node)
48
+ literal = integer_part(node)
49
+
50
+ if literal =~ OCTAL_ZERO_ONLY_REGEX && octal_zero_only?
51
+ return :octal_zero_only
52
+ elsif literal =~ OCTAL_REGEX && !octal_zero_only?
53
+ return :octal
54
+ end
55
+
56
+ case literal
57
+ when HEX_REGEX
58
+ :hex
59
+ when BINARY_REGEX
60
+ :binary
61
+ when DECIMAL_REGEX
62
+ :decimal
63
+ end
64
+ end
65
+
66
+ def octal_zero_only?
67
+ cop_config['EnforcedOctalStyle'] == 'zero_only'
68
+ end
69
+
70
+ def format_octal(source)
71
+ source.sub(/^0O?/, '0o')
72
+ end
73
+
74
+ def format_octal_zero_only(source)
75
+ source.sub(/^0[Oo]?/, '0')
76
+ end
77
+
78
+ def format_hex(source)
79
+ source.sub(/^0X/, '0x')
80
+ end
81
+
82
+ def format_binary(source)
83
+ source.sub(/^0B/, '0b')
84
+ end
85
+
86
+ def format_decimal(source)
87
+ source.sub(/^0[dD]/, '')
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -11,6 +11,7 @@ module RuboCop
11
11
  # digits for which an offense can be registered), but essentially it's
12
12
  # a Max parameter (the maximum number of something that's allowed).
13
13
  include ConfigurableMax
14
+ include IntegerNode
14
15
 
15
16
  MSG = 'Separate every 3 digits in the integer portion of a number ' \
16
17
  'with underscores(_).'.freeze
@@ -70,10 +71,6 @@ module RuboCop
70
71
  end
71
72
  end
72
73
 
73
- def integer_part(node)
74
- node.source.sub(/^[+-]/, '').split('.').first
75
- end
76
-
77
74
  def min_digits
78
75
  cop_config['MinDigits']
79
76
  end
@@ -147,13 +147,13 @@ module RuboCop
147
147
  def modifier_while?(node)
148
148
  node.loc.respond_to?(:keyword) &&
149
149
  %w(while until).include?(node.loc.keyword.source) &&
150
- node.loc.respond_to?(:end) && node.loc.end.nil?
150
+ node.modifier_form?
151
151
  end
152
152
 
153
153
  def rescue_modifier?(node)
154
- node &&
155
- node.rescue_type? &&
156
- (node.parent.nil? || !node.parent.kwbegin_type?)
154
+ node && node.rescue_type? &&
155
+ (node.parent.nil? || !(node.parent.kwbegin_type? ||
156
+ node.parent.ensure_type?))
157
157
  end
158
158
 
159
159
  # An internal class for correcting parallel assignment
@@ -202,6 +202,28 @@ module RuboCop
202
202
  _node, rescue_clause = *node.parent
203
203
  _, _, rescue_result = *rescue_clause
204
204
 
205
+ # If the parallel assignment uses a rescue modifier and it is the
206
+ # only contents of a method, then we want to make use of the
207
+ # implicit begin
208
+ if node.parent.parent && node.parent.parent.def_type?
209
+ super + def_correction(rescue_result)
210
+ else
211
+ begin_correction(rescue_result)
212
+ end
213
+ end
214
+
215
+ def correction_range
216
+ node.parent.source_range
217
+ end
218
+
219
+ private
220
+
221
+ def def_correction(rescue_result)
222
+ "\nrescue" \
223
+ "\n#{offset(node)}#{rescue_result.source}"
224
+ end
225
+
226
+ def begin_correction(rescue_result)
205
227
  "begin\n" \
206
228
  "#{indentation(node)}" \
207
229
  "#{assignment.join("\n#{indentation(node)}")}" \
@@ -209,10 +231,6 @@ module RuboCop
209
231
  "#{indentation(node)}#{rescue_result.source}" \
210
232
  "\n#{offset(node)}end"
211
233
  end
212
-
213
- def correction_range
214
- node.parent.source_range
215
- end
216
234
  end
217
235
 
218
236
  # An internal class for correcting parallel assignment
@@ -4,22 +4,22 @@
4
4
  module RuboCop
5
5
  module Cop
6
6
  module Style
7
- # This cop checks for uses of the deprecated methods Hash#has_key?
8
- # and Hash#has_value?
9
- class DeprecatedHashMethods < Cop
10
- MSG = '`Hash#%s` is deprecated in favor of `Hash#%s`.'.freeze
7
+ # This cop checks for uses of methods Hash#has_key? and Hash#has_value?
8
+ # Prefer to use Hash#key? and Hash#value? instead
9
+ class PreferredHashMethods < Cop
10
+ MSG = 'Use `Hash#%s` instead of `Hash#%s`.'.freeze
11
11
 
12
- DEPRECATED_METHODS = [:has_key?, :has_value?].freeze
12
+ PREFERRED_METHODS = [:has_key?, :has_value?].freeze
13
13
 
14
14
  def on_send(node)
15
15
  _receiver, method_name, *args = *node
16
16
  return unless args.size == 1 &&
17
- DEPRECATED_METHODS.include?(method_name)
17
+ PREFERRED_METHODS.include?(method_name)
18
18
 
19
19
  add_offense(node, :selector,
20
20
  format(MSG,
21
- method_name,
22
- proper_method_name(method_name)))
21
+ proper_method_name(method_name),
22
+ method_name))
23
23
  end
24
24
 
25
25
  def autocorrect(node)
@@ -32,17 +32,16 @@ module RuboCop
32
32
  end
33
33
 
34
34
  def parens_allowed?(node)
35
- child = node.children.first
36
- parent = node.parent
37
-
38
- # don't flag `break(1)`, etc
39
- (keyword_ancestor?(node) && parens_required?(node)) ||
35
+ # don't flag `()`
36
+ empty_parentheses?(node) ||
37
+ # don't flag `break(1)`, etc
38
+ (keyword_ancestor?(node) && parens_required?(node)) ||
40
39
  # don't flag `method ({key: value})`
41
- (child.hash_type? && first_arg?(node) && !parentheses?(parent)) ||
40
+ hash_literal_as_first_arg?(node) ||
42
41
  # don't flag `rescue(ExceptionClass)`
43
42
  rescue?(node) ||
44
43
  # don't flag `method (arg) { }`
45
- (arg_in_call_with_block?(node) && !parentheses?(parent)) ||
44
+ (arg_in_call_with_block?(node) && !parentheses?(node.parent)) ||
46
45
  # don't flag
47
46
  # ```
48
47
  # { a: (1
@@ -51,6 +50,15 @@ module RuboCop
51
50
  allowed_array_or_hash_element?(node)
52
51
  end
53
52
 
53
+ def empty_parentheses?(node)
54
+ node.children.empty?
55
+ end
56
+
57
+ def hash_literal_as_first_arg?(node)
58
+ child = node.children.first
59
+ child.hash_type? && first_arg?(node) && !parentheses?(node.parent)
60
+ end
61
+
54
62
  def check(begin_node)
55
63
  node = begin_node.children.first
56
64
  if keyword_with_redundant_parentheses?(node)
@@ -63,22 +71,24 @@ module RuboCop
63
71
  end
64
72
 
65
73
  def check_send(begin_node, node)
66
- if node.unary_operation?
67
- return if begin_node.chained?
74
+ return check_unary(begin_node, node) if node.unary_operation?
68
75
 
69
- # parens are not redundant in `(!recv.method arg)`
70
- node = node.children.first while node.unary_operation?
71
- if node.send_type?
72
- return unless method_call_with_redundant_parentheses?(node)
73
- end
76
+ return unless method_call_with_redundant_parentheses?(node)
77
+ return if call_chain_starts_with_int?(begin_node, node)
74
78
 
75
- offense(begin_node, 'an unary operation')
76
- else
77
- return unless method_call_with_redundant_parentheses?(node)
78
- return if call_chain_starts_with_int?(begin_node, node)
79
+ offense(begin_node, 'a method call')
80
+ end
81
+
82
+ def check_unary(begin_node, node)
83
+ return if begin_node.chained?
79
84
 
80
- offense(begin_node, 'a method call')
85
+ # parens are not redundant in `(!recv.method arg)`
86
+ node = node.children.first while node.unary_operation?
87
+ if node.send_type?
88
+ return unless method_call_with_redundant_parentheses?(node)
81
89
  end
90
+
91
+ offense(begin_node, 'an unary operation')
82
92
  end
83
93
 
84
94
  def offense(node, msg)