Created
May 3, 2012 18:47
-
-
Save schneems/2588053 to your computer and use it in GitHub Desktop.
Formatter Modifications
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
module Journey | |
### | |
# The Formatter class is used for formatting URLs. For example, parameters | |
# passed to +url_for+ in rails will eventually call Formatter#generate | |
class Formatter | |
attr_reader :routes | |
def initialize routes | |
@routes = routes | |
@cache = nil | |
end | |
def generate type, name, options, recall = {}, parameterize = nil | |
constraints = recall.merge options | |
match_route(name, constraints) do |route| | |
parameterized_parts = extract_parameterized_parts route, options, recall, parameterize | |
next unless verify_required_parts!(route, parameterized_parts) | |
params = options.dup.delete_if do |key, _| | |
parameterized_parts.key?(key) || route.defaults.key?(key) | |
end | |
return [route.format(parameterized_parts), params] | |
end | |
raise Router::RoutingError | |
end | |
def clear | |
@cache = nil | |
end | |
def find_missing_keys name, options, recall, parameterize = nil | |
constraints = recall.merge options | |
match_route name, constraints do |route| | |
parts = extract_parameterized_parts route, options, recall, parameterize | |
return missing_keys(route, parts) | |
end | |
end | |
private | |
def extract_parameterized_parts route, options, recall, parameterize = nil | |
constraints = recall.merge options | |
data = constraints.dup | |
keys_to_keep = route.parts.reverse.drop_while { |part| | |
!options.key?(part) || (options[part] || recall[part]).nil? | |
} | route.required_parts | |
(data.keys - keys_to_keep).each do |bad_key| | |
data.delete bad_key | |
end | |
parameterized_parts = data.dup | |
if parameterize | |
parameterized_parts.each do |k,v| | |
parameterized_parts[k] = parameterize.call(k, v) | |
end | |
end | |
parameterized_parts.keep_if { |_,v| v } | |
parameterized_parts | |
end | |
def named_routes | |
routes.named_routes | |
end | |
def match_route name, options | |
if named_routes.key? name | |
yield named_routes[name] | |
else | |
#routes = possibles(@cache, options.to_a) | |
routes = non_recursive(cache, options.to_a) | |
hash = routes.group_by { |_, r| | |
r.score options | |
} | |
hash.keys.sort.reverse_each do |score| | |
next if score < 0 | |
hash[score].sort_by { |i,_| i }.each do |_,route| | |
yield route | |
end | |
end | |
end | |
end | |
def non_recursive cache, options | |
routes = [] | |
stack = [cache] | |
while stack.any? | |
c = stack.shift | |
routes.concat c[:___routes] if c.key? :___routes | |
options.each do |pair| | |
stack << c[pair] if c.key? pair | |
end | |
end | |
routes | |
end | |
# returns an array populated with missing keys if any are present | |
def missing_keys route, parts | |
missing_keys = [] | |
tests = route.path.requirements | |
route.required_parts.all? { |key| | |
if tests.key? key | |
missing_keys << key unless /\A#{tests[key]}\Z/ === parts[key] | |
else | |
missing_keys << key unless parts[key] | |
end | |
} | |
missing_keys | |
end | |
def possibles cache, options, depth = 0 | |
cache.fetch(:___routes) { [] } + options.find_all { |pair| | |
cache.key? pair | |
}.map { |pair| | |
possibles(cache[pair], options, depth + 1) | |
}.flatten(1) | |
end | |
# returns boolean, true if no missing keys are present | |
def verify_required_parts! route, parts | |
missing_keys(route, parts).empty? | |
end | |
def build_cache | |
kash = {} | |
routes.each_with_index do |route, i| | |
money = kash | |
route.required_defaults.each do |tuple| | |
hash = (money[tuple] ||= {}) | |
money = hash | |
end | |
(money[:___routes] ||= []) << [i, route] | |
end | |
kash | |
end | |
def cache | |
@cache ||= build_cache | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment