Skip to content

Commit

Permalink
make tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
dubadub committed Jun 7, 2014
1 parent ffdad3b commit 675f06a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 5 deletions.
51 changes: 50 additions & 1 deletion lib/topo_sort.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
require "topo_sort/version"
require 'ostruct'

module TopoSort
# Your code goes here...
class SelfDependency < StandardError; end
class Cyclic < StandardError; end

extend self

#Take a hash of elements and their dependencies and sort
#them in an order where each element required is before
#the elements that require it.
#
#Example usage:
#
# nodes = { :a => nil, :b => :c, :c => :f, :d => :a, :e => :b, :f => nil }
# TopoSort.sort(nodes)
# #=> [:a, :f, :c, :b, :d, :e]
#
def sort(nodes)
@sorted = []

@vertices = nodes.inject({}) do |memo, (node, dependency)|
memo[node] = OpenStruct.new(
name: node,
dependency: dependency,
marked: false, #store the vertex has been visited by dfs
on_stack: false #to detect cycle
)
memo
end

nodes.each{ |(node, dep)| visit(@vertices[node]) unless @vertices[node].marked }

@sorted
end

protected

def visit(vertice)
vertice.marked = true
vertice.on_stack = true
if vertice.dependency && dependency = @vertices[vertice.dependency]
raise SelfDependency.new("sort failed: detected self-dependency for '#{vertice.name}'") if dependency == vertice
raise Cyclic.new("sort failed: detected cyclic dependency '#{vertice.name} => #{dependency.name}'") if dependency.on_stack
visit(dependency) unless dependency.marked
end
vertice.on_stack = false

@sorted.push vertice.name
end

end

8 changes: 4 additions & 4 deletions spec/lib/topo_sort_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
}

sorted = TopoSort.sort(nodes)
sorted.should == nodes
sorted.should == [:a, :b, :c]
end

it "should sort several nodes with one that has dependency" do
Expand All @@ -49,7 +49,7 @@
}

sorted = TopoSort.sort(nodes)
sorted.should == [:f, :c, :b, :e, :a, :d]
sorted.should == [:a, :f, :c, :b, :d, :e]
end

it "should raise error when node depends on themselve" do
Expand All @@ -58,7 +58,7 @@
b: nil,
c: :c
}
expect { TopoSort.sort(nodes) }.to raise_error(TopoSort::SelfDependency, /sort failed: detected self dependency/)
expect { TopoSort.sort(nodes) }.to raise_error(TopoSort::SelfDependency, /sort failed: detected self-dependency/)
end

it "should raise error when circular dependency is presented" do
Expand All @@ -70,6 +70,6 @@
e: nil,
f: :b
}
expect { TopoSort.sort(nodes) }.to raise_error(TopoSort::Cyclic, /sort failed: detcted cyclic dependency/)
expect { TopoSort.sort(nodes) }.to raise_error(TopoSort::Cyclic, /sort failed: detected cyclic dependency/)
end
end

0 comments on commit 675f06a

Please sign in to comment.