Class: RuboCop::Cop::Style::ParallelAssignment::AssignmentSorter
- Inherits:
-
Object
- Object
- RuboCop::Cop::Style::ParallelAssignment::AssignmentSorter
- Extended by:
- Macros
- Defined in:
- lib/rubocop/cop/style/parallel_assignment.rb
Overview
Topologically sorts the assignments with Kahn's algorithm. https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
Instance Method Summary collapse
-
#accesses?(rhs, lhs) ⇒ Boolean
lhsis an assignment method call likeobj.attr=orary[idx]=. -
#dependencies_for_assignment(assignment) ⇒ Object
Returns all the assignments which must come after
assignment(due to dependencies on the previous value of the assigned var). - #dependency?(lhs, rhs) ⇒ Boolean
-
#initialize(assignments) ⇒ AssignmentSorter
constructor
A new instance of AssignmentSorter.
- #matching_calls(node, receiver, method_name) ⇒ Object
- #tsort ⇒ Object
- #uses_var?(node) ⇒ Object
- #var_name(node) ⇒ Object
Constructor Details
#initialize(assignments) ⇒ AssignmentSorter
Returns a new instance of AssignmentSorter.
137 138 139 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 137 def initialize(assignments) @assignments = assignments end |
Instance Method Details
#accesses?(rhs, lhs) ⇒ Boolean
lhs is an assignment method call like obj.attr= or ary[idx]=.
Does rhs access the same value which is assigned by lhs?
184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 184 def accesses?(rhs, lhs) if lhs.method?(:[]=) # FIXME: Workaround `rubocop:disable` comment for JRuby. # rubocop:disable Performance/RedundantEqualityComparisonBlock matching_calls(rhs, lhs.receiver, :[]).any? { |args| args == lhs.arguments } # rubocop:enable Performance/RedundantEqualityComparisonBlock else access_method = lhs.method_name.to_s.chop.to_sym matching_calls(rhs, lhs.receiver, access_method).any? end end |
#dependencies_for_assignment(assignment) ⇒ Object
Returns all the assignments which must come after assignment
(due to dependencies on the previous value of the assigned var)
163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 163 def dependencies_for_assignment(assignment) my_lhs, _my_rhs = *assignment @assignments.filter_map do |other| # Exclude self, there are no dependencies in cases such as `a, b = a, b`. next if other == assignment _other_lhs, other_rhs = *other next unless dependency?(my_lhs, other_rhs) other end end |
#dependency?(lhs, rhs) ⇒ Boolean
177 178 179 180 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 177 def dependency?(lhs, rhs) uses_var?(rhs, var_name(lhs)) || (lhs.send_type? && lhs.assignment_method? && accesses?(rhs, lhs)) end |
#matching_calls(node, receiver, method_name) ⇒ Object
135 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 135 def_node_search :matching_calls, '(send %1 %2 $...)' |
#tsort ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 141 def tsort dependencies = @assignments.to_h do |assignment| [assignment, dependencies_for_assignment(assignment)] end result = [] while (matched_node, = dependencies.find { |_node, edges| edges.empty? }) dependencies.delete(matched_node) result.push(matched_node) dependencies.each do |node, edges| dependencies[node].delete(matched_node) if edges.include?(matched_node) end end # Cyclic dependency return nil if dependencies.any? result end |
#uses_var?(node) ⇒ Object
132 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 132 def_node_search :uses_var?, '{({lvar ivar cvar gvar} %) (const _ %)}' |
#var_name(node) ⇒ Object
129 |
# File 'lib/rubocop/cop/style/parallel_assignment.rb', line 129 def_node_matcher :var_name, '{(casgn _ $_) (_ $_)}' |