class RuboCop::Cop::Style::SwapValues

Enforces the use of shorthand-style swapping of 2 variables.

@safety

Autocorrection is unsafe, because the temporary variable used to
swap variables will be removed, but may be referred to elsewhere.

@example

# bad
tmp = x
x = y
y = tmp

# good
x, y = y, x

Constants

MSG
SIMPLE_ASSIGNMENT_TYPES

Public Instance Methods

"on_#{asgn_type}"(node)
Alias for: on_asgn
on_asgn(node) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 30
def on_asgn(node)
  return if allowed_assignment?(node)

  tmp_assign = node
  x_assign, y_assign = *node.right_siblings.take(2)
  return unless x_assign && y_assign && swapping_values?(tmp_assign, x_assign, y_assign)

  add_offense(node, message: message(x_assign, y_assign)) do |corrector|
    range = correction_range(tmp_assign, y_assign)
    corrector.replace(range, replacement(x_assign))
  end
end
Also aliased as: "on_#{asgn_type}"

Private Instance Methods

allowed_assignment?(node) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 47
def allowed_assignment?(node)
  node.parent&.mlhs_type? || node.parent&.shorthand_asgn?
end
correction_range(tmp_assign, y_assign) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 104
def correction_range(tmp_assign, y_assign)
  range_by_whole_lines(
    range_between(tmp_assign.source_range.begin_pos, y_assign.source_range.end_pos)
  )
end
lhs(node) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 81
def lhs(node)
  case node.type
  when :casgn
    namespace, name, = *node
    if namespace
      "#{namespace.const_name}::#{name}"
    else
      name.to_s
    end
  else
    node.children[0].to_s
  end
end
message(x_assign, y_assign) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 66
def message(x_assign, y_assign)
  format(
    MSG,
    x_line: x_assign.first_line,
    y_line: y_assign.first_line,
    replacement: replacement(x_assign)
  )
end
replacement(x_assign) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 75
def replacement(x_assign)
  x = lhs(x_assign)
  y = rhs(x_assign)
  "#{x}, #{y} = #{y}, #{x}"
end
rhs(node) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 95
def rhs(node)
  case node.type
  when :casgn
    node.children[2].source
  else
    node.children[1].source
  end
end
simple_assignment?(node) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 60
def simple_assignment?(node)
  return false unless node.respond_to?(:type)

  SIMPLE_ASSIGNMENT_TYPES.include?(node.type)
end
swapping_values?(tmp_assign, x_assign, y_assign) click to toggle source
# File lib/rubocop/cop/style/swap_values.rb, line 51
def swapping_values?(tmp_assign, x_assign, y_assign)
  simple_assignment?(tmp_assign) &&
    simple_assignment?(x_assign) &&
    simple_assignment?(y_assign) &&
    lhs(x_assign) == rhs(tmp_assign) &&
    lhs(y_assign) == rhs(x_assign) &&
    rhs(y_assign) == lhs(tmp_assign)
end