Created
March 8, 2011 01:53
-
-
Save tenderlove/859696 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/middleware/visitor.rb b/lib/middleware/visitor.rb | |
new file mode 100644 | |
index 0000000..fdfb96d | |
--- /dev/null | |
+++ b/lib/middleware/visitor.rb | |
@@ -0,0 +1,100 @@ | |
+module Middleware | |
+ class Visitor | |
+ class Node < Struct.new(:id, :name) | |
+ end | |
+ | |
+ class Edge < Struct.new(:from, :to, :name) | |
+ end | |
+ | |
+ def initialize | |
+ @nodes = [] | |
+ @edges = [] | |
+ @edge_stack = [] | |
+ @node_stack = [] | |
+ @seen = {} | |
+ end | |
+ | |
+ def accept o | |
+ visit o | |
+ nodes = @nodes.map { |node| | |
+ "#{node.id} [label=\"#{node.name}\"];" | |
+ }.join("\n") | |
+ edges = @edges.map { |edge| | |
+ "#{edge.from.id} -> #{edge.to.id} [label=\"#{edge.name}\"];" | |
+ }.join("\n") | |
+ | |
+ "digraph \"rack middleware\" {\n | |
+ | |
+node [ | |
+shape = \"box\" | |
+]; | |
+ #{nodes}\n#{edges}\n}" | |
+ end | |
+ | |
+ private | |
+ | |
+ def visit_Rack_Mount_RouteSet o | |
+ named_routes = o.instance_variable_get(:@named_routes) | |
+ named_routes.each do |k,v| | |
+ @edge_stack.push "@named_routes[#{k}]" | |
+ visit v | |
+ @edge_stack.pop | |
+ end | |
+ | |
+ routes = o.instance_variable_get(:@routes) | |
+ routes.each_with_index do |k,i| | |
+ @edge_stack.push "@routes[#{i}]" | |
+ visit k | |
+ @edge_stack.pop | |
+ end | |
+ end | |
+ | |
+ def visit_Rack_Mount_Route o | |
+ app = o.instance_variable_get(:@app) | |
+ @edge_stack.push :@app | |
+ visit app | |
+ @edge_stack.pop | |
+ end | |
+ | |
+ def visit o | |
+ method = "visit_#{o.class.name.gsub('::', '_')}" | |
+ | |
+ return if !o.respond_to?(:call) && !respond_to?(method, true) | |
+ | |
+ if @seen.key?(o) | |
+ unless @edge_stack.empty? | |
+ @edges << Edge.new(@node_stack.last, @seen[o], @edge_stack.last) | |
+ end | |
+ return | |
+ end | |
+ | |
+ node = Node.new(o.object_id, o.class.name) | |
+ | |
+ @seen[o] = node | |
+ @nodes << node | |
+ | |
+ unless @edge_stack.empty? | |
+ @edges << Edge.new(@node_stack.last, node, @edge_stack.last) | |
+ end | |
+ | |
+ @node_stack.push node | |
+ | |
+ if respond_to?(method, true) | |
+ send(method, o) | |
+ else | |
+ generic o | |
+ end | |
+ | |
+ @node_stack.pop | |
+ end | |
+ | |
+ def generic o | |
+ o.instance_variables.each do |ivar| | |
+ child = o.instance_variable_get(ivar) | |
+ @edge_stack.push ivar | |
+ visit child | |
+ @edge_stack.pop | |
+ end | |
+ end | |
+ end | |
+end | |
diff --git a/lib/rack/server.rb b/lib/rack/server.rb | |
index 6bf8771..f4bef58 100644 | |
--- a/lib/rack/server.rb | |
+++ b/lib/rack/server.rb | |
@@ -1,4 +1,5 @@ | |
require 'optparse' | |
+require 'middleware/visitor' | |
module Rack | |
class Server | |
@@ -228,6 +229,10 @@ module Rack | |
end | |
end | |
+ viz = Middleware::Visitor.new | |
+ ::File.open('/tmp/foo.dot', 'wb') { |f| | |
+ f.write viz.accept wrapped_app | |
+ } | |
server.run wrapped_app, options | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment