1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
# encoding: utf-8
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_STAR node
"*" + super
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
|