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
on_masgn(node)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 29 def on_masgn(node) lhs, rhs = *node lhs_elements = *lhs rhs_elements = [*rhs].compact # edge case for one constant return if allowed_lhs?(lhs) || allowed_rhs?(rhs) || allowed_masign?(lhs_elements, rhs_elements) add_offense(node) end
Private Instance Methods
add_self_to_getters(right_elements)
click to toggle source
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`.
# File lib/rubocop/cop/style/parallel_assignment.rb, line 111 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
allowed_lhs?(node)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 48 def allowed_lhs?(node) elements = *node # Account for edge cases using one variable with a comma # E.g.: `foo, = *bar` elements.one? || elements.any?(&:splat_type?) end
allowed_masign?(lhs_elements, rhs_elements)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 42 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
allowed_rhs?(node)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 56 def allowed_rhs?(node) # Edge case for one constant elements = [*node].compact # Account for edge case of `Constant::CONSTANT` !node.array_type? || return_of_method_call?(node) || elements.any?(&:splat_type?) end
assignment_corrector(node, order)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 83 def assignment_corrector(node, order) _assignment, modifier = *node.parent if modifier_statement?(node.parent) ModifierCorrector.new(node, config, order) elsif rescue_modifier?(modifier) RescueCorrector.new(node, config, order) else GenericCorrector.new(node, config, order) end end
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 70 def autocorrect(node) lambda do |corrector| left, right = *node left_elements = *left right_elements = [*right].compact order = find_valid_order(left_elements, right_elements) correction = assignment_corrector(node, order) corrector.replace(correction.correction_range, correction.correction) end end
find_valid_order(left_elements, right_elements)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 94 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 170 def modifier_statement?(node) node && %i[if while until].include?(node.type) && node.modifier_form? end
return_of_method_call?(node)
click to toggle source
# File lib/rubocop/cop/style/parallel_assignment.rb, line 66 def return_of_method_call?(node) node.block_type? || node.send_type? end