2012-12-19 15:54:47 -05:00
|
|
|
# encoding: utf-8
|
2013-08-07 14:13:11 -04:00
|
|
|
|
2012-12-19 15:54:47 -05:00
|
|
|
module ActionDispatch
|
2012-12-19 19:24:25 -05:00
|
|
|
module Journey # :nodoc:
|
2014-05-20 16:12:59 -04:00
|
|
|
class Format
|
|
|
|
ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
|
|
|
|
ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
|
|
|
|
|
|
|
|
class Parameter < Struct.new(:name, :escaper)
|
|
|
|
def escape(value); escaper.call value; end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.required_path(symbol)
|
|
|
|
Parameter.new symbol, ESCAPE_PATH
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.required_segment(symbol)
|
|
|
|
Parameter.new symbol, ESCAPE_SEGMENT
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(parts)
|
|
|
|
@parts = parts
|
|
|
|
@children = []
|
|
|
|
@parameters = []
|
|
|
|
|
|
|
|
parts.each_with_index do |object,i|
|
|
|
|
case object
|
|
|
|
when Journey::Format
|
|
|
|
@children << i
|
|
|
|
when Parameter
|
|
|
|
@parameters << i
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def evaluate(hash)
|
|
|
|
parts = @parts.dup
|
|
|
|
|
|
|
|
@parameters.each do |index|
|
|
|
|
param = parts[index]
|
2014-05-21 17:27:09 -04:00
|
|
|
value = hash[param.name]
|
|
|
|
return ''.freeze unless value
|
2014-05-20 16:12:59 -04:00
|
|
|
parts[index] = param.escape value
|
|
|
|
end
|
|
|
|
|
|
|
|
@children.each { |index| parts[index] = parts[index].evaluate(hash) }
|
|
|
|
|
|
|
|
parts.join
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-19 19:24:25 -05:00
|
|
|
module Visitors # :nodoc:
|
2012-12-19 15:54:47 -05:00
|
|
|
class Visitor # :nodoc:
|
2014-05-20 14:10:52 -04:00
|
|
|
DISPATCH_CACHE = {}
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def accept(node)
|
|
|
|
visit(node)
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit node
|
|
|
|
send(DISPATCH_CACHE[node.type], node)
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def binary(node)
|
|
|
|
visit(node.left)
|
|
|
|
visit(node.right)
|
|
|
|
end
|
|
|
|
def visit_CAT(n); binary(n); end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def nary(node)
|
|
|
|
node.children.each { |c| visit(c) }
|
|
|
|
end
|
|
|
|
def visit_OR(n); nary(n); end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
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
|
2014-05-20 14:10:52 -04:00
|
|
|
def visit_LITERAL(n); terminal(n); end
|
|
|
|
def visit_SYMBOL(n); terminal(n); end
|
|
|
|
def visit_SLASH(n); terminal(n); end
|
|
|
|
def visit_DOT(n); terminal(n); end
|
|
|
|
|
|
|
|
private_instance_methods(false).each do |pim|
|
|
|
|
next unless pim =~ /^visit_(.*)$/
|
|
|
|
DISPATCH_CACHE[$1.to_sym] = pim
|
2012-12-20 15:42:39 -05:00
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
2014-05-20 16:12:59 -04:00
|
|
|
|
|
|
|
class FormatBuilder < Visitor # :nodoc:
|
|
|
|
def accept(node); Journey::Format.new(super); end
|
|
|
|
def terminal(node); [node.left]; end
|
|
|
|
|
|
|
|
def binary(node)
|
|
|
|
visit(node.left) + visit(node.right)
|
|
|
|
end
|
|
|
|
|
|
|
|
def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
|
|
|
|
|
|
|
|
def visit_STAR(n)
|
|
|
|
[Journey::Format.required_path(n.left.to_sym)]
|
|
|
|
end
|
|
|
|
|
|
|
|
def visit_SYMBOL(n)
|
|
|
|
symbol = n.to_sym
|
|
|
|
if symbol == :controller
|
|
|
|
[Journey::Format.required_path(symbol)]
|
|
|
|
else
|
|
|
|
[Journey::Format.required_segment(symbol)]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
|
|
|
# Loop through the requirements AST
|
|
|
|
class Each < Visitor # :nodoc:
|
|
|
|
attr_reader :block
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def initialize(block)
|
2012-12-19 15:54:47 -05:00
|
|
|
@block = block
|
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit(node)
|
|
|
|
block.call(node)
|
2014-05-20 14:00:06 -04:00
|
|
|
super
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-19 19:24:25 -05:00
|
|
|
class String < Visitor # :nodoc:
|
2012-12-19 15:54:47 -05:00
|
|
|
private
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def binary(node)
|
2012-12-19 15:54:47 -05:00
|
|
|
[visit(node.left), visit(node.right)].join
|
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def nary(node)
|
|
|
|
node.children.map { |c| visit(c) }.join '|'
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def terminal(node)
|
2012-12-19 15:54:47 -05:00
|
|
|
node.left
|
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit_GROUP(node)
|
|
|
|
"(#{visit(node.left)})"
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-12-19 19:24:25 -05:00
|
|
|
class Dot < Visitor # :nodoc:
|
2012-12-19 15:54:47 -05:00
|
|
|
def initialize
|
|
|
|
@nodes = []
|
|
|
|
@edges = []
|
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def accept(node)
|
2012-12-19 15:54:47 -05:00
|
|
|
super
|
|
|
|
<<-eodot
|
|
|
|
digraph parse_tree {
|
|
|
|
size="8,5"
|
|
|
|
node [shape = none];
|
|
|
|
edge [dir = none];
|
|
|
|
#{@nodes.join "\n"}
|
|
|
|
#{@edges.join("\n")}
|
|
|
|
}
|
|
|
|
eodot
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2012-12-20 15:42:39 -05:00
|
|
|
|
|
|
|
def binary(node)
|
|
|
|
node.children.each do |c|
|
|
|
|
@edges << "#{node.object_id} -> #{c.object_id};"
|
|
|
|
end
|
|
|
|
super
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def nary(node)
|
|
|
|
node.children.each do |c|
|
|
|
|
@edges << "#{node.object_id} -> #{c.object_id};"
|
|
|
|
end
|
|
|
|
super
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def unary(node)
|
|
|
|
@edges << "#{node.object_id} -> #{node.left.object_id};"
|
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit_GROUP(node)
|
|
|
|
@nodes << "#{node.object_id} [label=\"()\"];"
|
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit_CAT(node)
|
|
|
|
@nodes << "#{node.object_id} [label=\"○\"];"
|
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit_STAR(node)
|
|
|
|
@nodes << "#{node.object_id} [label=\"*\"];"
|
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def visit_OR(node)
|
|
|
|
@nodes << "#{node.object_id} [label=\"|\"];"
|
|
|
|
super
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
def terminal(node)
|
|
|
|
value = node.left
|
2012-12-19 15:54:47 -05:00
|
|
|
|
2012-12-20 15:42:39 -05:00
|
|
|
@nodes << "#{node.object_id} [label=\"#{value}\"];"
|
|
|
|
end
|
2012-12-19 15:54:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|