aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/journey/visitors.rb
diff options
context:
space:
mode:
authorAndrew White <andyw@pixeltrix.co.uk>2012-12-19 20:54:47 +0000
committerAndrew White <andyw@pixeltrix.co.uk>2012-12-19 22:13:08 +0000
commit56fee39c392788314c44a575b3fd66e16a50c8b5 (patch)
treee12603fff0d1e7c69d021f822b4077a74b91ddc4 /actionpack/lib/action_dispatch/journey/visitors.rb
parentb225693a0d86f2e33c66049a69e5148e5c93b7cd (diff)
downloadrails-56fee39c392788314c44a575b3fd66e16a50c8b5.tar.gz
rails-56fee39c392788314c44a575b3fd66e16a50c8b5.tar.bz2
rails-56fee39c392788314c44a575b3fd66e16a50c8b5.zip
Integrate Journey into Action Dispatch
Move the Journey code underneath the ActionDispatch namespace so that we don't pollute the global namespace with names that may be used for models. Fixes rails/journey#49.
Diffstat (limited to 'actionpack/lib/action_dispatch/journey/visitors.rb')
-rw-r--r--actionpack/lib/action_dispatch/journey/visitors.rb188
1 files changed, 188 insertions, 0 deletions
diff --git a/actionpack/lib/action_dispatch/journey/visitors.rb b/actionpack/lib/action_dispatch/journey/visitors.rb
new file mode 100644
index 0000000000..b3f4796607
--- /dev/null
+++ b/actionpack/lib/action_dispatch/journey/visitors.rb
@@ -0,0 +1,188 @@
+# encoding: utf-8
+module ActionDispatch
+ module Journey
+ module Visitors
+ class Visitor # :nodoc:
+ DISPATCH_CACHE = Hash.new { |h,k|
+ h[k] = "visit_#{k}"
+ }
+
+ def accept node
+ visit node
+ end
+
+ private
+ def visit node
+ send DISPATCH_CACHE[node.type], node
+ end
+
+ def binary node
+ visit node.left
+ visit node.right
+ end
+ def visit_CAT(n); binary(n); end
+
+ def nary node
+ node.children.each { |c| visit c }
+ end
+ def visit_OR(n); nary(n); end
+
+ def unary node
+ visit node.left
+ end
+ def visit_GROUP(n); unary(n); end
+ def visit_STAR(n); unary(n); end
+
+ def terminal node; end
+ %w{ LITERAL SYMBOL SLASH DOT }.each do |t|
+ class_eval %{ def visit_#{t}(n); terminal(n); end }, __FILE__, __LINE__
+ end
+ end
+
+ ##
+ # Loop through the requirements AST
+ class Each < Visitor # :nodoc:
+ attr_reader :block
+
+ def initialize block
+ @block = block
+ end
+
+ def visit node
+ super
+ block.call node
+ end
+ end
+
+ class String < Visitor
+ private
+
+ def binary node
+ [visit(node.left), visit(node.right)].join
+ end
+
+ def nary node
+ node.children.map { |c| visit c }.join '|'
+ end
+
+ def terminal node
+ node.left
+ end
+
+ def visit_GROUP node
+ "(#{visit node.left})"
+ end
+ end
+
+ ###
+ # Used for formatting urls (url_for)
+ class Formatter < Visitor
+ attr_reader :options, :consumed
+
+ def initialize options
+ @options = options
+ @consumed = {}
+ end
+
+ private
+ def visit_GROUP node
+ if consumed == options
+ nil
+ else
+ route = visit node.left
+ route.include?("\0") ? nil : route
+ end
+ end
+
+ def terminal node
+ node.left
+ end
+
+ def binary node
+ [visit(node.left), visit(node.right)].join
+ end
+
+ def nary node
+ node.children.map { |c| visit c }.join
+ end
+
+ def visit_SYMBOL node
+ key = node.to_sym
+
+ if value = options[key]
+ consumed[key] = value
+ Router::Utils.escape_path(value)
+ else
+ "\0"
+ end
+ end
+ end
+
+ class Dot < Visitor
+ def initialize
+ @nodes = []
+ @edges = []
+ end
+
+ def accept node
+ super
+ <<-eodot
+ digraph parse_tree {
+ size="8,5"
+ node [shape = none];
+ edge [dir = none];
+ #{@nodes.join "\n"}
+ #{@edges.join("\n")}
+ }
+ eodot
+ end
+
+ private
+ def binary node
+ node.children.each do |c|
+ @edges << "#{node.object_id} -> #{c.object_id};"
+ end
+ super
+ end
+
+ def nary node
+ node.children.each do |c|
+ @edges << "#{node.object_id} -> #{c.object_id};"
+ end
+ super
+ end
+
+ def unary node
+ @edges << "#{node.object_id} -> #{node.left.object_id};"
+ super
+ end
+
+ def visit_GROUP node
+ @nodes << "#{node.object_id} [label=\"()\"];"
+ super
+ end
+
+ def visit_CAT node
+ @nodes << "#{node.object_id} [label=\"○\"];"
+ super
+ end
+
+ def visit_STAR node
+ @nodes << "#{node.object_id} [label=\"*\"];"
+ super
+ end
+
+ def visit_OR node
+ @nodes << "#{node.object_id} [label=\"|\"];"
+ super
+ end
+
+ def terminal node
+ value = node.left
+
+ @nodes << "#{node.object_id} [label=\"#{value}\"];"
+ end
+ end
+ end
+ end
+end