rubocop 0.34.2 → 0.35.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/README.md +103 -31
  4. data/config/default.yml +32 -2
  5. data/config/disabled.yml +24 -0
  6. data/config/enabled.yml +20 -2
  7. data/lib/rubocop.rb +13 -0
  8. data/lib/rubocop/ast_node.rb +48 -0
  9. data/lib/rubocop/cli.rb +9 -0
  10. data/lib/rubocop/config.rb +8 -6
  11. data/lib/rubocop/config_loader.rb +30 -8
  12. data/lib/rubocop/cop/commissioner.rb +1 -1
  13. data/lib/rubocop/cop/cop.rb +19 -6
  14. data/lib/rubocop/cop/lint/circular_argument_reference.rb +33 -2
  15. data/lib/rubocop/cop/lint/debugger.rb +9 -56
  16. data/lib/rubocop/cop/lint/end_alignment.rb +29 -9
  17. data/lib/rubocop/cop/lint/eval.rb +6 -2
  18. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +24 -6
  19. data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
  20. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +10 -1
  21. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  22. data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
  23. data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
  24. data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
  25. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  26. data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
  27. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
  28. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
  29. data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
  30. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
  31. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
  32. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  33. data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
  34. data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
  35. data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
  36. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  37. data/lib/rubocop/cop/performance/detect.rb +5 -1
  38. data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
  39. data/lib/rubocop/cop/performance/size.rb +1 -1
  40. data/lib/rubocop/cop/performance/string_replacement.rb +14 -8
  41. data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
  42. data/lib/rubocop/cop/style/align_hash.rb +1 -12
  43. data/lib/rubocop/cop/style/align_parameters.rb +19 -7
  44. data/lib/rubocop/cop/style/and_or.rb +42 -13
  45. data/lib/rubocop/cop/style/block_comments.rb +4 -2
  46. data/lib/rubocop/cop/style/block_delimiters.rb +57 -18
  47. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  48. data/lib/rubocop/cop/style/command_literal.rb +2 -10
  49. data/lib/rubocop/cop/style/copyright.rb +5 -3
  50. data/lib/rubocop/cop/style/documentation.rb +9 -6
  51. data/lib/rubocop/cop/style/dot_position.rb +6 -0
  52. data/lib/rubocop/cop/style/double_negation.rb +4 -15
  53. data/lib/rubocop/cop/style/each_with_object.rb +17 -4
  54. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -5
  55. data/lib/rubocop/cop/style/encoding.rb +10 -4
  56. data/lib/rubocop/cop/style/extra_spacing.rb +23 -13
  57. data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
  58. data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
  59. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
  60. data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
  61. data/lib/rubocop/cop/style/for.rb +2 -1
  62. data/lib/rubocop/cop/style/if_unless_modifier.rb +31 -0
  63. data/lib/rubocop/cop/style/indent_hash.rb +67 -37
  64. data/lib/rubocop/cop/style/indentation_width.rb +1 -1
  65. data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
  66. data/lib/rubocop/cop/style/method_call_parentheses.rb +8 -0
  67. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
  68. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +8 -13
  69. data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
  70. data/lib/rubocop/cop/style/next.rb +18 -0
  71. data/lib/rubocop/cop/style/parallel_assignment.rb +57 -15
  72. data/lib/rubocop/cop/style/predicate_name.rb +7 -2
  73. data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
  74. data/lib/rubocop/cop/style/single_line_methods.rb +7 -5
  75. data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
  76. data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
  77. data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
  78. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
  79. data/lib/rubocop/cop/style/trailing_comma.rb +9 -6
  80. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
  81. data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
  82. data/lib/rubocop/cop/style/variable_name.rb +5 -0
  83. data/lib/rubocop/cop/style/word_array.rb +2 -1
  84. data/lib/rubocop/cop/team.rb +17 -4
  85. data/lib/rubocop/cop/util.rb +5 -0
  86. data/lib/rubocop/cop/variable_force/locatable.rb +1 -1
  87. data/lib/rubocop/formatter/base_formatter.rb +1 -1
  88. data/lib/rubocop/formatter/disabled_config_formatter.rb +22 -10
  89. data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
  90. data/lib/rubocop/node_pattern.rb +390 -0
  91. data/lib/rubocop/options.rb +48 -36
  92. data/lib/rubocop/processed_source.rb +3 -1
  93. data/lib/rubocop/rake_task.rb +1 -1
  94. data/lib/rubocop/remote_config.rb +60 -0
  95. data/lib/rubocop/result_cache.rb +4 -2
  96. data/lib/rubocop/runner.rb +33 -10
  97. data/lib/rubocop/token.rb +2 -1
  98. data/lib/rubocop/version.rb +1 -1
  99. data/lib/rubocop/warning.rb +11 -0
  100. data/relnotes/v0.35.0.md +210 -0
  101. data/rubocop.gemspec +2 -2
  102. metadata +20 -6
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # appropriate value with --auto-gen-config.
7
7
  module ConfigurableMax
8
8
  def max=(value)
9
- cfg = self.config_to_allow_offenses ||= {}
9
+ cfg = config_to_allow_offenses
10
10
  value = [cfg[parameter_name], value].max if cfg[parameter_name]
11
11
  cfg[parameter_name] = value
12
12
  end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  return false unless node.defs_type?
34
34
  return false unless node.parent
35
35
 
36
- node.parent.children.any? do |c|
36
+ node.parent.children.compact.any? do |c|
37
37
  c.class_type? && c.loc.name.is?(name.to_s)
38
38
  end
39
39
  end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking for a line break before the first
6
+ # element in a multi-line collection.
7
+ module FirstElementLineBreak
8
+ def autocorrect(node)
9
+ ->(corrector) { corrector.insert_before(node.loc.expression, "\n") }
10
+ end
11
+
12
+ private
13
+
14
+ def check_method_line_break(node, children)
15
+ return if children.empty?
16
+
17
+ return unless method_uses_parens?(node, children.first)
18
+
19
+ check_children_line_break(node, children)
20
+ end
21
+
22
+ def method_uses_parens?(node, limit)
23
+ source = node.loc.expression.source_line[0...limit.loc.column]
24
+ source =~ /\s*\(\s*$/
25
+ end
26
+
27
+ def check_children_line_break(node, children, start = node)
28
+ return if children.size < 2
29
+
30
+ line = start.loc.line
31
+ min = children.min_by { |n| n.loc.first_line }
32
+ return if line != min.loc.first_line
33
+
34
+ max = children.max_by { |n| n.loc.last_line }
35
+ return if line == max.loc.last_line
36
+
37
+ add_offense(min, :expression, self.class::MSG)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  def check_negative_conditional(node)
9
9
  condition, _body, _rest = *node
10
10
 
11
- # Look at last expression of contents if there's a parenthesis
11
+ # Look at last expression of contents if there are parentheses
12
12
  # around condition.
13
13
  condition = condition.children.last while condition.type == :begin
14
14
  return unless condition.type == :send
@@ -6,21 +6,10 @@ module RuboCop
6
6
  # putting parentheses around an assignment to indicate "I know I'm using an
7
7
  # assignment as a condition. It's not a mistake."
8
8
  module SafeAssignment
9
- def safe_assignment?(node)
10
- return false unless node.type == :begin
11
- return false unless node.children.size == 1
9
+ extend NodePattern::Macros
12
10
 
13
- child = node.children.first
14
- case child.type
15
- when :send
16
- _receiver, method_name, _args = *child
17
- method_name.to_s.end_with?('=')
18
- when *Util::EQUALS_ASGN_NODES
19
- true
20
- else
21
- false
22
- end
23
- end
11
+ def_node_matcher :safe_assignment?,
12
+ '(begin {equals_asgn? asgn_method_call?})'
24
13
 
25
14
  def safe_assignment_allowed?
26
15
  cop_config['AllowSafeAssignment']
@@ -30,7 +30,7 @@ module RuboCop
30
30
  end
31
31
 
32
32
  def max_line_length
33
- cop_config && cop_config['MaxLineLength'] ||
33
+ cop_config['MaxLineLength'] ||
34
34
  config.for_cop('Metrics/LineLength')['Max']
35
35
  end
36
36
 
@@ -55,7 +55,7 @@ module RuboCop
55
55
  end
56
56
 
57
57
  def comment_lines
58
- @comment_lines ||= processed_source.comments.map(&:location).map(&:line)
58
+ @comment_lines ||= processed_source.comments.map { |c| c.location.line }
59
59
  end
60
60
  end
61
61
  end
@@ -57,7 +57,11 @@ module RuboCop
57
57
  else
58
58
  preferred_method
59
59
  end
60
- first_range = node.loc.dot.join(node.loc.selector)
60
+
61
+ first_range = Parser::Source::Range.new(
62
+ receiver.loc.expression.source,
63
+ receiver.loc.end.end_pos,
64
+ receiver.loc.end.end_pos).join(node.loc.selector)
61
65
 
62
66
  receiver, _args, _body = *receiver if receiver.block_type?
63
67
 
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # Do not compute the size of statically sized objects.
7
+ class FixedSize < Cop
8
+ MSG = 'Do not compute the size of statically sized objects.'.freeze
9
+ COUNTERS = [:count, :length, :size].freeze
10
+ STATIC_SIZED_TYPES = [:array, :hash, :str, :sym].freeze
11
+
12
+ def on_send(node)
13
+ variable, method, arg = *node
14
+ return unless variable
15
+ return unless COUNTERS.include?(method)
16
+ return unless STATIC_SIZED_TYPES.include?(variable.type)
17
+ return if contains_splat?(variable)
18
+ return if contains_double_splat?(variable)
19
+ return if string_argument?(arg)
20
+ if node.parent
21
+ return if node.parent.casgn_type? || node.parent.block_type?
22
+ end
23
+ add_offense(node, :expression)
24
+ end
25
+
26
+ private
27
+
28
+ def contains_splat?(node)
29
+ return unless node.array_type?
30
+
31
+ node.children.any? do |child|
32
+ child.respond_to?(:splat_type?) && child.splat_type?
33
+ end
34
+ end
35
+
36
+ def contains_double_splat?(node)
37
+ return unless node.hash_type?
38
+
39
+ node.children.any? do |child|
40
+ child.respond_to?(:kwsplat_type?) && child.kwsplat_type?
41
+ end
42
+ end
43
+
44
+ def string_argument?(node)
45
+ node && !node.str_type?
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  return unless method == :count
34
34
  return unless array?(receiver) || hash?(receiver)
35
35
  return if node.parent && node.parent.block_type?
36
- return if args && args.block_pass_type?
36
+ return if args
37
37
 
38
38
  add_offense(node, node.loc.selector)
39
39
  end
@@ -20,7 +20,7 @@ module RuboCop
20
20
  # 'a b c'.delete(' ')
21
21
  class StringReplacement < Cop
22
22
  MSG = 'Use `%s` instead of `%s`.'
23
- DETERMINISTIC_REGEX = /^[\w\s\-,."']+$/.freeze
23
+ DETERMINISTIC_REGEX = /^[\w\s\-,"']+$/.freeze
24
24
  REGEXP_CONSTRUCTOR_METHODS = [:new, :compile].freeze
25
25
  GSUB_METHODS = [:gsub, :gsub!].freeze
26
26
  DETERMINISTIC_TYPES = [:regexp, :str, :send].freeze
@@ -32,16 +32,17 @@ module RuboCop
32
32
  def on_send(node)
33
33
  _string, method, first_param, second_param = *node
34
34
  return unless GSUB_METHODS.include?(method)
35
- return unless second_param && second_param.str_type?
35
+ return unless string?(second_param)
36
36
  return unless DETERMINISTIC_TYPES.include?(first_param.type)
37
37
 
38
- first_source = first_source(first_param)
38
+ first_source, options = first_source(first_param)
39
39
  second_source, = *second_param
40
40
 
41
41
  return if first_source.nil?
42
42
 
43
43
  if regex?(first_param)
44
44
  return unless first_source =~ DETERMINISTIC_REGEX
45
+ return if options
45
46
  end
46
47
 
47
48
  return if first_source.length != 1
@@ -53,7 +54,7 @@ module RuboCop
53
54
 
54
55
  def autocorrect(node)
55
56
  _string, method, first_param, second_param = *node
56
- first_source = first_source(first_param)
57
+ first_source, = first_source(first_param)
57
58
  second_source, = *second_param
58
59
  replacement_method = replacement_method(method,
59
60
  first_source,
@@ -74,17 +75,21 @@ module RuboCop
74
75
 
75
76
  private
76
77
 
78
+ def string?(node)
79
+ node && node.str_type?
80
+ end
81
+
77
82
  def first_source(first_param)
78
83
  case first_param.type
79
84
  when :regexp, :send
80
85
  return nil unless regex?(first_param)
81
86
 
82
- source, = extract_source(first_param)
87
+ source, options = extract_source(first_param)
83
88
  when :str
84
89
  source, = *first_param
85
90
  end
86
91
 
87
- source
92
+ [source, options]
88
93
  end
89
94
 
90
95
  def extract_source(node)
@@ -97,9 +102,10 @@ module RuboCop
97
102
  end
98
103
 
99
104
  def source_from_regex_literal(node)
100
- regex, = *node
105
+ regex, options = *node
101
106
  source, = *regex
102
- source
107
+ options, = *options
108
+ [source, options]
103
109
  end
104
110
 
105
111
  def source_from_regex_constructor(node)
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks for correct grammar when using ActiveSupport's
7
+ # core extensions to the numeric classes.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # 3.day.ago
12
+ # 1.months.ago
13
+ #
14
+ # # good
15
+ # 3.days.ago
16
+ # 1.month.ago
17
+ class PluralizationGrammar < Cop
18
+ SINGULAR_DURATION_METHODS = { second: :seconds,
19
+ minute: :minutes,
20
+ hour: :hours,
21
+ day: :days,
22
+ week: :weeks,
23
+ fortnight: :fortnights,
24
+ month: :months,
25
+ year: :years }
26
+
27
+ PLURAL_DURATION_METHODS = SINGULAR_DURATION_METHODS.invert
28
+
29
+ MSG = 'Prefer `%s.%s`.'
30
+
31
+ def on_send(node)
32
+ receiver, method_name, *_args = *node
33
+ return if receiver.nil?
34
+ return unless duration_method?(method_name)
35
+ return unless literal_number?(receiver)
36
+ number, = *receiver
37
+ if singular_receiver?(number) && plural_method?(method_name)
38
+ add_offense(node,
39
+ :expression,
40
+ format(MSG, number, singularize(method_name)))
41
+ elsif plural_receiver?(number) && singular_method?(method_name)
42
+ add_offense(node,
43
+ :expression,
44
+ format(MSG, number, pluralize(method_name)))
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def autocorrect(node)
51
+ lambda do |corrector|
52
+ method_name = node.loc.selector.source
53
+ replacement = if plural_method?(method_name)
54
+ singularize(method_name)
55
+ else
56
+ pluralize(method_name)
57
+ end
58
+ corrector.replace(node.loc.selector, replacement)
59
+ end
60
+ end
61
+
62
+ def plural_method?(method_name)
63
+ method_name.to_s.end_with?('s')
64
+ end
65
+
66
+ def singular_method?(method_name)
67
+ !plural_method?(method_name)
68
+ end
69
+
70
+ def singular_receiver?(number)
71
+ number == 1
72
+ end
73
+
74
+ def plural_receiver?(number)
75
+ !singular_receiver?(number)
76
+ end
77
+
78
+ def literal_number?(node)
79
+ node.int_type? || node.float_type?
80
+ end
81
+
82
+ def pluralize(method_name)
83
+ SINGULAR_DURATION_METHODS.fetch(method_name.to_sym).to_s
84
+ end
85
+
86
+ def singularize(method_name)
87
+ PLURAL_DURATION_METHODS.fetch(method_name.to_sym).to_s
88
+ end
89
+
90
+ def duration_method?(method_name)
91
+ SINGULAR_DURATION_METHODS.key?(method_name) ||
92
+ PLURAL_DURATION_METHODS.key?(method_name)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -156,7 +156,7 @@ module RuboCop
156
156
  def on_hash(node)
157
157
  return if ignored_node?(node)
158
158
  return if node.children.empty?
159
- return unless multiline?(node)
159
+ return unless node.multiline?
160
160
 
161
161
  @alignment_for_hash_rockets ||=
162
162
  new_alignment('EnforcedHashRocketStyle')
@@ -201,17 +201,6 @@ module RuboCop
201
201
  node.loc.begin
202
202
  end
203
203
 
204
- # Returns true if the hash spans multiple lines
205
- def multiline?(node)
206
- return false unless node.loc.expression.source.include?("\n")
207
-
208
- return false if node.children[1..-1].all? do |child|
209
- !begins_its_line?(child.loc.expression)
210
- end
211
-
212
- true
213
- end
214
-
215
204
  def alignment_for(pair)
216
205
  if pair.loc.operator.is?('=>')
217
206
  @alignment_for_hash_rockets
@@ -3,23 +3,33 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Here we check if the parameters on a multi-line method call are
7
- # aligned.
6
+ # Here we check if the parameters on a multi-line method call or
7
+ # definition are aligned.
8
8
  class AlignParameters < Cop
9
9
  include AutocorrectAlignment
10
-
11
- MSG = 'Align the parameters of a method call if they span ' \
12
- 'more than one line.'
10
+ include OnMethodDef
13
11
 
14
12
  def on_send(node)
15
13
  _receiver, method, *args = *node
16
14
 
17
15
  return if method == :[]=
18
- return if args.size <= 1
16
+ return if args.size < 2
17
+
18
+ check_alignment(args, base_column(node, args))
19
+ end
19
20
 
21
+ def on_method_def(node, _method_name, args, _body)
22
+ args = args.children
23
+ return if args.size < 2
20
24
  check_alignment(args, base_column(node, args))
21
25
  end
22
26
 
27
+ def message(node)
28
+ type = node.parent.send_type? ? 'call' : 'definition'
29
+ "Align the parameters of a method #{type} if they span " \
30
+ 'more than one line.'
31
+ end
32
+
23
33
  private
24
34
 
25
35
  def fixed_indentation?
@@ -38,7 +48,9 @@ module RuboCop
38
48
  end
39
49
 
40
50
  def target_method_lineno(node)
41
- if node.loc.selector
51
+ if node.def_type? || node.defs_type?
52
+ node.loc.keyword.line
53
+ elsif node.loc.selector
42
54
  node.loc.selector.line
43
55
  else
44
56
  # l.(1) has no selector, so we use the opening parenthesis instead
@@ -63,25 +63,54 @@ module RuboCop
63
63
  replacement = (node.type == :and ? '&&' : '||')
64
64
  lambda do |corrector|
65
65
  [expr1, expr2].each do |expr|
66
- _receiver, _method_name, *args = *expr
67
- next unless correctable?(expr)
68
-
69
- sb = expr.loc.expression.source_buffer
70
- begin_paren = expr.loc.selector.end_pos
71
- end_paren = begin_paren + 1
72
- range = Parser::Source::Range.new(sb, begin_paren, end_paren)
73
- corrector.replace(range, '(')
74
- corrector.insert_after(args.last.loc.expression, ')')
66
+ if expr.send_type?
67
+ correct_send(expr, corrector)
68
+ elsif expr.return_type?
69
+ correct_other(expr, corrector)
70
+ elsif expr.assignment?
71
+ correct_other(expr, corrector)
72
+ end
75
73
  end
76
74
  corrector.replace(node.loc.operator, replacement)
77
75
  end
78
76
  end
79
77
 
80
- def correctable?(expr)
81
- return false unless expr.type == :send
82
- _receiver, method_name, *args = *expr
78
+ def correct_send(node, corrector)
79
+ receiver, method_name, *args = *node
80
+ if method_name == :!
81
+ # ! is a special case:
82
+ # 'x and !obj.method arg' can be auto-corrected if we
83
+ # recurse down a level and add parens to 'obj.method arg'
84
+ # however, 'not x' also parses as (send x :!)
85
+
86
+ if node.loc.selector.source == '!'
87
+ node = receiver
88
+ _receiver, _method_name, *args = *node
89
+ elsif node.loc.selector.source == 'not'
90
+ return correct_other(node, corrector)
91
+ else
92
+ fail 'unrecognized unary negation operator'
93
+ end
94
+ end
95
+ return unless correctable_send?(node)
96
+
97
+ sb = node.loc.expression.source_buffer
98
+ begin_paren = node.loc.selector.end_pos
99
+ range = Parser::Source::Range.new(sb, begin_paren, begin_paren + 1)
100
+ corrector.replace(range, '(')
101
+ corrector.insert_after(args.last.loc.expression, ')')
102
+ end
103
+
104
+ def correct_other(node, corrector)
105
+ return unless node.loc.expression.begin.source != '('
106
+ corrector.insert_before(node.loc.expression, '(')
107
+ corrector.insert_after(node.loc.expression, ')')
108
+ end
109
+
110
+ def correctable_send?(node)
111
+ _receiver, method_name, *args = *node
83
112
  # don't clobber if we already have a starting paren
84
- return false unless !expr.loc.begin || expr.loc.begin.source != '('
113
+ return false unless !node.loc.begin || node.loc.begin.source != '('
85
114
  # don't touch anything unless we are sure it is a method call.
86
115
  return false unless args.last && method_name.to_s =~ /[a-z]/
87
116