A directed acyclic graph that is tuned to hold named dependencies
A directed edge of a {DependencyGraph} @attr [Vertex] origin The origin of the directed edge @attr [Vertex] destination The destination of the directed edge @attr [Object] requirement The requirement the directed edge represents
@return [{String => Vertex}] the vertices of the dependency graph, keyed
by {Vertex#name}
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 48
def initialize
@vertices = {}
end
Initializes an empty dependency graph
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 30
def self.tsort(vertices)
TSort.tsort(
lambda { |b| vertices.each(&b) },
lambda { |v, &b| (v.successors & vertices).each(&b) }
)
end
Topologically sorts the given vertices. @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
all belong to the same graph.
@return [Array<Vertex>] The sorted vertices.
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 81
def ==(other)
return false unless other
vertices.each do |name, vertex|
other_vertex = other.vertex_named(name)
return false unless other_vertex
return false unless other_vertex.successors.map(&:name).to_set == vertex.successors.map(&:name).to_set
end
end
@return [Boolean] whether the two dependency graphs are equal, determined
by a recursive traversal of each {#root_vertices} and its {Vertex#successors}
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 95
def add_child_vertex(name, payload, parent_names, requirement)
vertex = add_vertex(name, payload)
parent_names.each do |parent_name|
unless parent_name
vertex.root = true
next
end
parent_node = vertex_named(parent_name)
add_edge(parent_node, vertex, requirement)
end
vertex
end
@param [String] name @param [Object] payload @param [Array<String>] parent_names @param [Object] requirement the requirement that is requiring the child @return [void]
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 150
def add_edge(origin, destination, requirement)
if destination.path_to?(origin)
raise CircularDependencyError.new([origin, destination])
end
add_edge_no_circular(origin, destination, requirement)
end
Adds a new {Edge} to the dependency graph @param [Vertex] origin @param [Vertex] destination @param [Object] requirement the requirement that this edge represents @return [Edge] the added edge
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 161
def add_edge_no_circular(origin, destination, requirement)
edge = Edge.new(origin, destination, requirement)
origin.outgoing_edges << edge
destination.incoming_edges << edge
edge
end
Adds a new {Edge} to the dependency graph without checking for circularity.
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 112
def add_vertex(name, payload, root = false)
vertex = vertices[name] ||= Vertex.new(name, payload)
vertex.payload ||= payload
vertex.root ||= root
vertex
end
Adds a vertex with the given name, or updates the existing one. @param [String] name @param [Object] payload @return [Vertex] the vertex that was added to ‘self`
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 123
def detach_vertex_named(name)
return unless vertex = vertices.delete(name)
vertex.outgoing_edges.each do |e|
v = e.destination
v.incoming_edges.delete(e)
detach_vertex_named(v.name) unless v.root? || v.predecessors.any?
end
end
Detaches the {#vertex_named} ‘name` {Vertex} from the graph, recursively removing any non-root vertices that were orphaned in the process @param [String] name @return [void]
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 12
def each
vertices.values.each { |v| yield v }
end
Enumerates through the vertices of the graph. @return [Array<Vertex>] The graph’s vertices.
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 55
def initialize_copy(other)
super
@vertices = {}
traverse = lambda do |new_v, old_v|
return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
old_v.outgoing_edges.each do |edge|
destination = add_vertex(edge.destination.name, edge.destination.payload)
add_edge_no_circular(new_v, destination, edge.requirement)
traverse.call(destination, edge.destination)
end
end
other.vertices.each do |name, vertex|
new_vertex = add_vertex(name, vertex.payload, vertex.root?)
new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
traverse.call(new_vertex, vertex)
end
end
Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices} are properly copied. @param [DependencyGraph] other the graph to copy.
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 74
def inspect
"#{self.class}:#{vertices.values.inspect}"
end
@return [String] a string suitable for debugging
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 140
def root_vertex_named(name)
vertex = vertex_named(name)
vertex if vertex && vertex.root?
end
@param [String] name @return [Vertex,nil] the root vertex with the given name
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 22
def tsort_each_child(vertex, &block)
vertex.successors.each(&block)
end
@visibility private
# File tmp/rubies/ruby-2.3.8/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb, line 134
def vertex_named(name)
vertices[name]
end
@param [String] name @return [Vertex,nil] the vertex with the given name