Skip to content

Commit

Permalink
Merge pull request #1166 from nanoc/fix-cycle-finding
Browse files Browse the repository at this point in the history
Handle tails in dependency cycles
  • Loading branch information
denisdefreyne committed Apr 22, 2017
2 parents 10e2519 + c369887 commit a18e229
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 11 deletions.
46 changes: 35 additions & 11 deletions lib/nanoc/base/entities/directed_graph.rb
Expand Up @@ -158,18 +158,42 @@ def delete_vertex(v)

# @group Querying the graph

# Returns a cycle if there is any.
def any_cycle
path = [@vertices.keys.first]

loop do
nexts = direct_successors_of(path.last)
cycle_start_index = path.find_index { |node| nexts.include?(node) }
if cycle_start_index
break path[cycle_start_index..-1]
elsif nexts.empty?
break nil
else
path << nexts.sample
all_paths.lazy.map { |path| cycle_in_path(path) }.find(&:itself)
end

# Given a potentially closed path, returns a cycle if there is any.
def cycle_in_path(path)
vertex = path.last
index = path.index(vertex)

if index < path.size - 1
path[index..-2]
end
end

# Yields all paths (including potentially closed ones).
def all_paths
Enumerator.new do |y|
@vertices.keys.each do |vertex|
dfs_from(vertex) do |path|
y << path
end
end
end
end

# Yields all paths (including potentially closed ones) starting from the given vertex.
def dfs_from(vertex, path_so_far = [])
new_path = path_so_far + [vertex]
yield(new_path)

unless path_so_far.include?(vertex)
direct_successors_of(vertex).each do |next_vertex|
dfs_from(next_vertex, new_path) do |path|
yield(path)
end
end
end
end
Expand Down
12 changes: 12 additions & 0 deletions spec/nanoc/base/directed_graph_spec.rb
Expand Up @@ -27,6 +27,18 @@
it { is_expected.to eq([2, 3]) }
end

context 'one cycle with tail' do
before do
graph.add_edge(1, 2)
graph.add_edge(2, 20)
graph.add_edge(20, 21)
graph.add_edge(2, 3)
graph.add_edge(3, 1)
end

it { is_expected.to eq([1, 2, 3]) }
end

context 'large cycle' do
before do
graph.add_edge(1, 2)
Expand Down

0 comments on commit a18e229

Please sign in to comment.