rubocop 1.5.0 → 1.7.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +52 -7
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +14 -0
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +21 -8
  7. data/lib/rubocop/config.rb +8 -5
  8. data/lib/rubocop/config_loader.rb +10 -6
  9. data/lib/rubocop/config_loader_resolver.rb +21 -4
  10. data/lib/rubocop/config_obsoletion.rb +64 -262
  11. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  12. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  13. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  14. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  17. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  18. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  20. data/lib/rubocop/config_validator.rb +11 -4
  21. data/lib/rubocop/cop/base.rb +17 -15
  22. data/lib/rubocop/cop/cop.rb +2 -2
  23. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  24. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
  25. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  26. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
  27. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
  28. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +1 -1
  29. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  30. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +26 -0
  31. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  32. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  33. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
  34. data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
  35. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  36. data/lib/rubocop/cop/layout/space_before_brackets.rb +64 -0
  37. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
  38. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
  39. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
  40. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
  41. data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
  42. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  43. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
  44. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
  45. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  46. data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
  47. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  48. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  49. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  50. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  51. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
  52. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  53. data/lib/rubocop/cop/registry.rb +10 -0
  54. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
  55. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  56. data/lib/rubocop/cop/style/collection_methods.rb +14 -1
  57. data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
  58. data/lib/rubocop/cop/style/float_division.rb +44 -1
  59. data/lib/rubocop/cop/style/for.rb +2 -0
  60. data/lib/rubocop/cop/style/hash_except.rb +95 -0
  61. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  62. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  63. data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
  64. data/lib/rubocop/cop/style/lambda_call.rb +2 -1
  65. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -0
  66. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
  67. data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
  68. data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
  69. data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
  70. data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
  71. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  72. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  73. data/lib/rubocop/cop/style/redundant_argument.rb +21 -2
  74. data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
  75. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  76. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  77. data/lib/rubocop/cop/style/single_line_methods.rb +4 -0
  78. data/lib/rubocop/cop/style/sole_nested_conditional.rb +24 -8
  79. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  80. data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
  81. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  82. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  83. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  84. data/lib/rubocop/cop/util.rb +3 -1
  85. data/lib/rubocop/ext/regexp_node.rb +31 -9
  86. data/lib/rubocop/ext/regexp_parser.rb +21 -3
  87. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  88. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  89. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  90. data/lib/rubocop/lockfile.rb +40 -0
  91. data/lib/rubocop/options.rb +9 -9
  92. data/lib/rubocop/rspec/cop_helper.rb +0 -4
  93. data/lib/rubocop/rspec/expect_offense.rb +34 -22
  94. data/lib/rubocop/runner.rb +16 -1
  95. data/lib/rubocop/target_finder.rb +4 -2
  96. data/lib/rubocop/util.rb +16 -0
  97. data/lib/rubocop/version.rb +8 -2
  98. metadata +33 -5
@@ -9,6 +9,12 @@ module RuboCop
9
9
  # In rare cases where only one iteration (or at most one iteration) is intended behavior,
10
10
  # the code should be refactored to use `if` conditionals.
11
11
  #
12
+ # NOTE: Block methods that are used with `Enumerable`s are considered to be loops.
13
+ #
14
+ # `IgnoredPatterns` can be used to match against the block receiver in order to allow
15
+ # code that would otherwise be registered as an offense (eg. `times` used not in an
16
+ # `Enumerable` context).
17
+ #
12
18
  # @example
13
19
  # # bad
14
20
  # while node
@@ -70,7 +76,16 @@ module RuboCop
70
76
  # raise NotFoundError
71
77
  # end
72
78
  #
79
+ # # bad
80
+ # 2.times { raise ArgumentError }
81
+ #
82
+ # @example IgnoredPatterns: [/(exactly|at_least|at_most)\(\d+\)\.times/] (default)
83
+ #
84
+ # # good
85
+ # exactly(2).times { raise StandardError }
73
86
  class UnreachableLoop < Base
87
+ include IgnoredPattern
88
+
74
89
  MSG = 'This loop will have at most one iteration.'
75
90
 
76
91
  def on_while(node)
@@ -91,6 +106,8 @@ module RuboCop
91
106
  return false unless node.block_type?
92
107
 
93
108
  send_node = node.send_node
109
+ return false if matches_ignored_pattern?(send_node.source)
110
+
94
111
  send_node.enumerable_method? || send_node.enumerator_method? || send_node.method?(:loop)
95
112
  end
96
113
 
@@ -124,7 +124,7 @@ module RuboCop
124
124
  end
125
125
 
126
126
  def classlike_node?(node)
127
- CLASSLIKE_TYPES.include?(node.type)
127
+ CLASSLIKE_TYPES.include?(node&.type)
128
128
  end
129
129
 
130
130
  def foldable_node?(node)
@@ -71,7 +71,7 @@ module RuboCop
71
71
  end
72
72
 
73
73
  def qualified_legacy_cop_name(cop_name)
74
- legacy_cop_names = RuboCop::ConfigObsoletion::OBSOLETE_COPS.keys
74
+ legacy_cop_names = RuboCop::ConfigObsoletion.legacy_cop_names
75
75
 
76
76
  legacy_cop_names.detect do |legacy_cop_name|
77
77
  legacy_cop_name.split('/')[1] == cop_name
@@ -14,7 +14,10 @@ module RuboCop
14
14
  return if part_of_ignored_node?(node)
15
15
 
16
16
  if offense?(node)
17
- add_offense(node) { opposite_style_detected }
17
+ add_offense(node) do |corrector|
18
+ opposite_style_detected
19
+ autocorrect(corrector, node) if respond_to?(:autocorrect, true)
20
+ end
18
21
  else
19
22
  correct_style_detected
20
23
  end
@@ -3,7 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Naming
6
- # This cop makes sure that accessor methods are named properly.
6
+ # This cop makes sure that accessor methods are named properly. Applies
7
+ # to both instance and class methods.
8
+ #
9
+ # NOTE: Offenses are only registered for methods with the expected
10
+ # arity. Getters (`get_attribute`) must have no arguments to be
11
+ # registered, and setters (`set_attribute(value)`) must have exactly
12
+ # one.
7
13
  #
8
14
  # @example
9
15
  # # bad
@@ -21,6 +27,14 @@ module RuboCop
21
27
  # # good
22
28
  # def attribute
23
29
  # end
30
+ #
31
+ # # accepted, incorrect arity for getter
32
+ # def get_value(attr)
33
+ # end
34
+ #
35
+ # # accepted, incorrect arity for setter
36
+ # def set_value
37
+ # end
24
38
  class AccessorMethodName < Base
25
39
  MSG_READER = 'Do not prefix reader method names with `get_`.'
26
40
  MSG_WRITER = 'Do not prefix writer method names with `set_`.'
@@ -4,7 +4,9 @@ module RuboCop
4
4
  module Cop
5
5
  module Naming
6
6
  # This cop checks for memoized methods whose instance variable name
7
- # does not match the method name.
7
+ # does not match the method name. Applies to both regular methods
8
+ # (defined with `def`) and dynamic methods (defined with
9
+ # `define_method` or `define_singleton_method`).
8
10
  #
9
11
  # This cop can be configured with the EnforcedStyleForLeadingUnderscores
10
12
  # directive. It can be configured to allow for memoized instance variables
@@ -48,6 +50,17 @@ module RuboCop
48
50
  # @foo ||= calculate_expensive_thing(helper_variable)
49
51
  # end
50
52
  #
53
+ # # good
54
+ # define_method(:foo) do
55
+ # @foo ||= calculate_expensive_thing
56
+ # end
57
+ #
58
+ # # good
59
+ # define_method(:foo) do
60
+ # return @foo if defined?(@foo)
61
+ # @foo = calculate_expensive_thing
62
+ # end
63
+ #
51
64
  # @example EnforcedStyleForLeadingUnderscores: required
52
65
  # # bad
53
66
  # def foo
@@ -79,6 +92,17 @@ module RuboCop
79
92
  # @_foo = calculate_expensive_thing
80
93
  # end
81
94
  #
95
+ # # good
96
+ # define_method(:foo) do
97
+ # @_foo ||= calculate_expensive_thing
98
+ # end
99
+ #
100
+ # # good
101
+ # define_method(:foo) do
102
+ # return @_foo if defined?(@_foo)
103
+ # @_foo = calculate_expensive_thing
104
+ # end
105
+ #
82
106
  # @example EnforcedStyleForLeadingUnderscores :optional
83
107
  # # bad
84
108
  # def foo
@@ -105,6 +129,16 @@ module RuboCop
105
129
  # return @_foo if defined?(@_foo)
106
130
  # @_foo = calculate_expensive_thing
107
131
  # end
132
+ #
133
+ # # good
134
+ # define_method(:foo) do
135
+ # @foo ||= calculate_expensive_thing
136
+ # end
137
+ #
138
+ # # good
139
+ # define_method(:foo) do
140
+ # @_foo ||= calculate_expensive_thing
141
+ # end
108
142
  class MemoizedInstanceVariableName < Base
109
143
  include ConfigurableEnforcedStyle
110
144
 
@@ -112,17 +146,27 @@ module RuboCop
112
146
  'method name `%<method>s`. Use `@%<suggested_var>s` instead.'
113
147
  UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
114
148
  'with `_`. Use `@%<suggested_var>s` instead.'
149
+ DYNAMIC_DEFINE_METHODS = %i[define_method define_singleton_method].to_set.freeze
150
+
151
+ def_node_matcher :method_definition?, <<~PATTERN
152
+ ${
153
+ (block (send _ %DYNAMIC_DEFINE_METHODS ({sym str} $_)) ...)
154
+ (def $_ ...)
155
+ (defs _ $_ ...)
156
+ }
157
+ PATTERN
115
158
 
116
159
  # rubocop:disable Metrics/AbcSize
117
160
  def on_or_asgn(node)
118
161
  lhs, _value = *node
119
162
  return unless lhs.ivasgn_type?
120
- return unless (method_node = node.each_ancestor(:def, :defs).first)
163
+
164
+ method_node, method_name = find_definition(node)
165
+ return unless method_node
121
166
 
122
167
  body = method_node.body
123
168
  return unless body == node || body.children.last == node
124
169
 
125
- method_name = method_node.method_name
126
170
  return if matches?(method_name, lhs)
127
171
 
128
172
  msg = format(
@@ -147,11 +191,10 @@ module RuboCop
147
191
  arg = node.arguments.first
148
192
  return unless arg.ivar_type?
149
193
 
150
- method_node = node.each_ancestor(:def, :defs).first
194
+ method_node, method_name = find_definition(node)
151
195
  return unless method_node
152
196
 
153
197
  var_name = arg.children.first
154
- method_name = method_node.method_name
155
198
  defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
156
199
  return if matches?(method_name, ivar_assign)
157
200
 
@@ -174,6 +217,17 @@ module RuboCop
174
217
  'EnforcedStyleForLeadingUnderscores'
175
218
  end
176
219
 
220
+ def find_definition(node)
221
+ # Methods can be defined in a `def` or `defs`,
222
+ # or dynamically via a `block` node.
223
+ node.each_ancestor(:def, :defs, :block).each do |ancestor|
224
+ method_node, method_name = method_definition?(ancestor)
225
+ return [method_node, method_name] if method_node
226
+ end
227
+
228
+ nil
229
+ end
230
+
177
231
  def matches?(method_name, ivar_assign)
178
232
  return true if ivar_assign.nil? || method_name == :initialize
179
233
 
@@ -104,6 +104,8 @@ module RuboCop
104
104
  def on_arg(node)
105
105
  @node = node
106
106
  name, = *node
107
+ return if allowed_identifier?(name)
108
+
107
109
  check_name(node, name, node.loc.name)
108
110
  end
109
111
  alias on_lvasgn on_arg
@@ -139,7 +141,7 @@ module RuboCop
139
141
  end
140
142
 
141
143
  def allowed_identifier?(name)
142
- allowed_identifiers.include?(name.to_s)
144
+ allowed_identifiers.include?(name.to_s.delete('@'))
143
145
  end
144
146
 
145
147
  def allowed_identifiers
@@ -204,6 +204,12 @@ module RuboCop
204
204
  to_h[cop_name].first
205
205
  end
206
206
 
207
+ def freeze
208
+ clear_enrollment_queue
209
+ unqualified_cop_names # build cache
210
+ super
211
+ end
212
+
207
213
  @global = new
208
214
 
209
215
  class << self
@@ -228,6 +234,10 @@ module RuboCop
228
234
  @global = previous
229
235
  end
230
236
 
237
+ def self.reset!
238
+ @global = new
239
+ end
240
+
231
241
  private
232
242
 
233
243
  def initialize_copy(reg)
@@ -87,7 +87,9 @@ module RuboCop
87
87
  return if allow_modifiers_on_symbols?(node)
88
88
 
89
89
  if offense?(node)
90
- add_offense(node.loc.selector) if opposite_style_detected
90
+ add_offense(node.loc.selector) do
91
+ opposite_style_detected
92
+ end
91
93
  else
92
94
  correct_style_detected
93
95
  end
@@ -14,8 +14,9 @@ module RuboCop
14
14
  #
15
15
  # # good
16
16
  # ?\C-\M-d
17
- class CharacterLiteral < Cop
17
+ class CharacterLiteral < Base
18
18
  include StringHelp
19
+ extend AutoCorrector
19
20
 
20
21
  MSG = 'Do not use the character literal - ' \
21
22
  'use string literal instead.'
@@ -26,17 +27,15 @@ module RuboCop
26
27
  node.source.size.between?(2, 3)
27
28
  end
28
29
 
29
- def autocorrect(node)
30
- lambda do |corrector|
31
- string = node.source[1..-1]
30
+ def autocorrect(corrector, node)
31
+ string = node.source[1..-1]
32
32
 
33
- # special character like \n
34
- # or ' which needs to use "" or be escaped.
35
- if string.length == 2 || string == "'"
36
- corrector.replace(node, %("#{string}"))
37
- elsif string.length == 1 # normal character
38
- corrector.replace(node, "'#{string}'")
39
- end
33
+ # special character like \n
34
+ # or ' which needs to use "" or be escaped.
35
+ if string.length == 2 || string == "'"
36
+ corrector.replace(node, %("#{string}"))
37
+ elsif string.length == 1 # normal character
38
+ corrector.replace(node, "'#{string}'")
40
39
  end
41
40
  end
42
41
 
@@ -48,7 +48,7 @@ module RuboCop
48
48
  end
49
49
 
50
50
  def on_send(node)
51
- return unless node.arguments.one? && node.first_argument.block_pass_type?
51
+ return unless implicit_block?(node)
52
52
 
53
53
  check_method_node(node)
54
54
  end
@@ -64,9 +64,22 @@ module RuboCop
64
64
  end
65
65
  end
66
66
 
67
+ def implicit_block?(node)
68
+ return false unless node.arguments.any?
69
+
70
+ node.last_argument.block_pass_type? ||
71
+ node.last_argument.sym_type? && methods_accepting_symbol.include?(node.method_name.to_s)
72
+ end
73
+
67
74
  def message(node)
68
75
  format(MSG, prefer: preferred_method(node.method_name), current: node.method_name)
69
76
  end
77
+
78
+ # Some enumerable methods accept a bare symbol (ie. _not_ Symbol#to_proc) instead
79
+ # of a block.
80
+ def methods_accepting_symbol
81
+ Array(cop_config['MethodsAcceptingSymbol'])
82
+ end
70
83
  end
71
84
  end
72
85
  end
@@ -4,12 +4,15 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # This cop checks for comments put on the same line as some keywords.
7
- # These keywords are: `begin`, `class`, `def`, `end`, `module`.
7
+ # These keywords are: `class`, `module`, `def`, `begin`, `end`.
8
8
  #
9
9
  # Note that some comments
10
10
  # (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`)
11
11
  # are allowed.
12
12
  #
13
+ # Auto-correction removes comments from `end` keyword and keeps comments
14
+ # for `class`, `module`, `def` and `begin` above the keyword.
15
+ #
13
16
  # @example
14
17
  # # bad
15
18
  # if condition
@@ -34,16 +37,17 @@ module RuboCop
34
37
  # y
35
38
  # end
36
39
  class CommentedKeyword < Base
40
+ include RangeHelp
41
+ extend AutoCorrector
42
+
37
43
  MSG = 'Do not place comments on the same line as the ' \
38
44
  '`%<keyword>s` keyword.'
39
45
 
40
46
  def on_new_investigation
41
47
  processed_source.comments.each do |comment|
42
- next unless (match = line(comment).match(/(?<keyword>\S+).*#/))
48
+ next unless (match = line(comment).match(/(?<keyword>\S+).*#/)) && offensive?(comment)
43
49
 
44
- if offensive?(comment)
45
- add_offense(comment, message: format(MSG, keyword: match[:keyword]))
46
- end
50
+ register_offense(comment, match[:keyword])
47
51
  end
48
52
  end
49
53
 
@@ -60,6 +64,19 @@ module RuboCop
60
64
  ].freeze
61
65
  ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
62
66
 
67
+ def register_offense(comment, matched_keyword)
68
+ add_offense(comment, message: format(MSG, keyword: matched_keyword)) do |corrector|
69
+ range = range_with_surrounding_space(range: comment.loc.expression, newlines: false)
70
+ corrector.remove(range)
71
+
72
+ unless matched_keyword == 'end'
73
+ corrector.insert_before(
74
+ range.source_buffer.line_range(comment.loc.line), "#{comment.text}\n"
75
+ )
76
+ end
77
+ end
78
+ end
79
+
63
80
  def offensive?(comment)
64
81
  line = line(comment)
65
82
  KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
@@ -41,6 +41,8 @@ module RuboCop
41
41
  # a.fdiv(b)
42
42
  class FloatDivision < Base
43
43
  include ConfigurableEnforcedStyle
44
+ extend AutoCorrector
45
+
44
46
  MESSAGES = {
45
47
  left_coerce: 'Prefer using `.to_f` on the left side.',
46
48
  right_coerce: 'Prefer using `.to_f` on the right side.',
@@ -64,7 +66,20 @@ module RuboCop
64
66
  PATTERN
65
67
 
66
68
  def on_send(node)
67
- add_offense(node) if offense_condition?(node)
69
+ return unless offense_condition?(node)
70
+
71
+ add_offense(node) do |corrector|
72
+ case style
73
+ when :left_coerce, :single_coerce
74
+ add_to_f_method(corrector, node.receiver)
75
+ remove_to_f_method(corrector, node.first_argument)
76
+ when :right_coerce
77
+ remove_to_f_method(corrector, node.receiver)
78
+ add_to_f_method(corrector, node.first_argument)
79
+ when :fdiv
80
+ correct_from_slash_to_fdiv(corrector, node, node.receiver, node.first_argument)
81
+ end
82
+ end
68
83
  end
69
84
 
70
85
  private
@@ -87,6 +102,34 @@ module RuboCop
87
102
  def message(_node)
88
103
  MESSAGES[style]
89
104
  end
105
+
106
+ def add_to_f_method(corrector, node)
107
+ corrector.insert_after(node, '.to_f') unless node.send_type? && node.method?(:to_f)
108
+ end
109
+
110
+ def remove_to_f_method(corrector, send_node)
111
+ corrector.remove(send_node.loc.dot)
112
+ corrector.remove(send_node.loc.selector)
113
+ end
114
+
115
+ def correct_from_slash_to_fdiv(corrector, node, receiver, argument)
116
+ receiver_source = extract_receiver_source(receiver)
117
+ argument_source = extract_receiver_source(argument)
118
+
119
+ if argument.respond_to?(:parenthesized?) && !argument.parenthesized?
120
+ argument_source = "(#{argument_source})"
121
+ end
122
+
123
+ corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
124
+ end
125
+
126
+ def extract_receiver_source(node)
127
+ if node.send_type? && node.method?(:to_f)
128
+ node.receiver.source
129
+ else
130
+ node.source
131
+ end
132
+ end
90
133
  end
91
134
  end
92
135
  end