class RuboCop::Cop::Style::ParallelAssignment

Checks for simple usages of parallel assignment. This will only complain when the number of variables being assigned matched the number of assigning variables.

@example

# bad
a, b, c = 1, 2, 3
a, b, c = [1, 2, 3]

# good
one, two = *foo
a, b = foo()
a, b = b, a

a = 1
b = 2
c = 3

Constants

MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 57
def autocorrect(node)
  lambda do |corrector|
    left, right = *node
    left_elements = *left
    right_elements = [*right].compact
    order = find_valid_order(left_elements, right_elements)

    assignment_corrector =
      if modifier_statement?(node.parent)
        ModifierCorrector.new(node, config, order)
      elsif rescue_modifier?(node.parent)
        RescueCorrector.new(node, config, order)
      else
        GenericCorrector.new(node, config, order)
      end

    corrector.replace(assignment_corrector.correction_range,
                      assignment_corrector.correction)
  end
end
on_masgn(node) click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 30
def on_masgn(node)
  left, right = *node
  left_elements = *left
  right_elements = [*right].compact # edge case for one constant

  # only complain when the number of variables matches
  return if left_elements.size != right_elements.size

  # account for edge cases using one variable with a comma
  return if left_elements.size == 1

  # account for edge case of Constant::CONSTANT
  return unless right.array_type?

  # allow mass assignment as the return of a method call
  return if right.block_type? || right.send_type?

  # allow mass assignment when using splat
  return if (left_elements + right_elements).any?(&:splat_type?)

  order = find_valid_order(left_elements, right_elements)
  # For `a, b = b, a` or similar, there is no valid order
  return if order.nil?

  add_offense(node, :expression)
end

Private Instance Methods

find_valid_order(left_elements, right_elements) click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 80
def find_valid_order(left_elements, right_elements)
  # arrange left_elements in an order such that no corresponding right
  # element refers to a left element earlier in the sequence
  # this can be done using an algorithm called a "topological sort"
  # fortunately for us, Ruby's stdlib contains an implementation
  assignments = left_elements.zip(right_elements)

  begin
    AssignmentSorter.new(assignments).tsort
  rescue TSort::Cyclic
    nil
  end
end
modifier_statement?(node) click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 140
def modifier_statement?(node)
  node &&
    ((node.if_type? && modifier_if?(node)) ||
    ((node.while_type? || node.until_type?) && modifier_while?(node)))
end
modifier_while?(node) click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 146
def modifier_while?(node)
  node.loc.respond_to?(:keyword) &&
    %w(while until).include?(node.loc.keyword.source) &&
    node.loc.respond_to?(:end) && node.loc.end.nil?
end
rescue_modifier?(node) click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 152
def rescue_modifier?(node)
  node &&
    node.rescue_type? &&
    (node.parent.nil? || !node.parent.kwbegin_type?)
end