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
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 31 def on_masgn(node) # rubocop:disable Metrics/AbcSize rhs = node.rhs rhs = rhs.body if rhs.rescue_type? rhs_elements = Array(rhs).compact # edge case for one constant return if allowed_lhs?(node.assignments) || allowed_rhs?(rhs) || allowed_masign?(node.assignments, rhs_elements) range = node.source_range.begin.join(rhs.source_range.end) add_offense(range) do |corrector| autocorrect(corrector, node, rhs) end end
Private Instance Methods
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 108 def add_self_to_getters(right_elements) right_elements.map do |e| implicit_self_getter?(e) { |var| s(:send, s(:self), var) } || e end end
Converts (send nil :something) nodes to (send (:self) :something). This makes the sorting algorithm work for expressions such as ‘self.a, self.b = b, a`.
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 61 def allowed_lhs?(elements) # Account for edge cases using one variable with a comma # E.g.: `foo, = *bar` elements.one? || elements.any?(&:splat_type?) end
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 55 def allowed_masign?(lhs_elements, rhs_elements) lhs_elements.size != rhs_elements.size || !find_valid_order(lhs_elements, add_self_to_getters(rhs_elements)) end
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 67 def allowed_rhs?(node) # Edge case for one constant elements = Array(node).compact # Account for edge case of `Constant::CONSTANT` !node.array_type? || elements.any?(&:splat_type?) end
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 75 def assignment_corrector(node, rhs, order) if node.parent&.rescue_type? _assignment, modifier = *node.parent else _assignment, modifier = *rhs.parent end if modifier_statement?(node.parent) ModifierCorrector.new(node, rhs, modifier, config, order) elsif rescue_modifier?(modifier) RescueCorrector.new(node, rhs, modifier, config, order) else GenericCorrector.new(node, rhs, modifier, config, order) end end
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 48 def autocorrect(corrector, node, rhs) order = find_valid_order(node.assignments, Array(rhs).compact) correction = assignment_corrector(node, rhs, order) corrector.replace(correction.correction_range, correction.correction) end
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 91 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
Source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 174 def modifier_statement?(node) return false unless node node.basic_conditional? && node.modifier_form? end