Permalink
Browse files

translate AST to a formatter before url generation

  • Loading branch information...
tenderlove committed May 20, 2014
1 parent 5300844 commit e883db02bce5d5f06628dc9eae51c8f526a4df97
@@ -76,7 +76,8 @@ def format(path_options)
value.to_s == defaults[key].to_s && !required_parts.include?(key)
end
- Visitors::Formatter.new(path_options).accept(path.spec)
+ format = Visitors::FormatBuilder.new.accept(path.spec)
+ format.evaluate path_options
end
def optimized_path
@@ -2,6 +2,52 @@
module ActionDispatch
module Journey # :nodoc:
+ 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]
+ value = hash.fetch(param.name) { return ''.freeze }
+ parts[index] = param.escape value
+ end
+
+ @children.each { |index| parts[index] = parts[index].evaluate(hash) }
+
+ parts.join
+ end
+ end
+
module Visitors # :nodoc:
class Visitor # :nodoc:
DISPATCH_CACHE = {}
@@ -45,6 +91,30 @@ def visit_DOT(n); terminal(n); end
end
end
+ 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
+
# Loop through the requirements AST
class Each < Visitor # :nodoc:
attr_reader :block

0 comments on commit e883db0

Please sign in to comment.