# frozen_string_literal: true module RuboCop module Cop module Style # This cop checks for division with integers coerced to floats. # It is recommended to either always use `fdiv` or coerce one side only. # This cop also provides other options for code consistency. # # @example EnforcedStyle: single_coerce (default) # # bad # a.to_f / b.to_f # # # good # a.to_f / b # a / b.to_f # # @example EnforcedStyle: left_coerce # # bad # a / b.to_f # a.to_f / b.to_f # # # good # a.to_f / b # # @example EnforcedStyle: right_coerce # # bad # a.to_f / b # a.to_f / b.to_f # # # good # a / b.to_f # # @example EnforcedStyle: fdiv # # bad # a / b.to_f # a.to_f / b # a.to_f / b.to_f # # # good # a.fdiv(b) class FloatDivision < Base include ConfigurableEnforcedStyle MESSAGES = { left_coerce: 'Prefer using `.to_f` on the left side.', right_coerce: 'Prefer using `.to_f` on the right side.', single_coerce: 'Prefer using `.to_f` on one side only.', fdiv: 'Prefer using `fdiv` for float divisions.' }.freeze def_node_matcher :right_coerce?, <<~PATTERN (send _ :/ (send _ :to_f)) PATTERN def_node_matcher :left_coerce?, <<~PATTERN (send (send _ :to_f) :/ _) PATTERN def_node_matcher :both_coerce?, <<~PATTERN (send (send _ :to_f) :/ (send _ :to_f)) PATTERN def_node_matcher :any_coerce?, <<~PATTERN {(send _ :/ (send _ :to_f)) (send (send _ :to_f) :/ _)} PATTERN def on_send(node) add_offense(node) if offense_condition?(node) end private def offense_condition?(node) case style when :left_coerce right_coerce?(node) when :right_coerce left_coerce?(node) when :single_coerce both_coerce?(node) when :fdiv any_coerce?(node) else false end end def message(_node) MESSAGES[style] end end end end end