lib/usher/node.rb in joshbuddy-usher-0.4.8 vs lib/usher/node.rb in joshbuddy-usher-0.4.10

- old
+ new

@@ -4,28 +4,37 @@ class Node Response = Struct.new(:path, :params) - attr_reader :lookup + attr_reader :lookup, :greedy_lookup attr_accessor :terminates, :exclusive_type, :parent, :value, :request_methods, :globs_capture_separators def initialize(parent, value) @parent = parent @value = value @lookup = Hash.new + @greedy_lookup = Hash.new @exclusive_type = nil end def upgrade_lookup @lookup = FuzzyHash.new(@lookup) end + def upgrade_greedy_lookup + @greedy_lookup = FuzzyHash.new(@greedy_lookup) + end + def depth @depth ||= @parent && @parent.is_a?(Node) ? @parent.depth + 1 : 0 end + def greedy? + !@greedy_lookup.empty? + end + def self.root(route_set, request_methods, globs_capture_separators) root = self.new(route_set, nil) root.request_methods = request_methods root.globs_capture_separators = globs_capture_separators root @@ -67,51 +76,73 @@ parts.unshift(key) current_node.lookup[nil] ||= Node.new(current_node, Route::RequestMethod.new(current_node.exclusive_type, nil)) end else key.globs_capture_separators = globs_capture_separators if key.is_a?(Route::Variable) - - if !key.is_a?(Route::Variable) + + case key + when Route::Variable + if key.greedy? + if key.regex_matcher + current_node.upgrade_greedy_lookup + current_node.greedy_lookup[key.regex_matcher] ||= Node.new(current_node, key) + else + current_node.greedy_lookup[nil] ||= Node.new(current_node, key) + end + else + if key.regex_matcher + current_node.upgrade_lookup + current_node.lookup[key.regex_matcher] ||= Node.new(current_node, key) + else + current_node.lookup[nil] ||= Node.new(current_node, key) + end + end + else current_node.upgrade_lookup if key.is_a?(Regexp) current_node.lookup[key] ||= Node.new(current_node, key) - elsif key.regex_matcher - current_node.upgrade_lookup - current_node.lookup[key.regex_matcher] ||= Node.new(current_node, key) - else - current_node.lookup[nil] ||= Node.new(current_node, key) - end + end + end current_node = target_node end current_node.terminates = path end route end - def find(usher, request, path, params = []) + def find(usher, request, original_path, path, params = [], position = 0) if exclusive_type [lookup[request.send(exclusive_type)], lookup[nil]].each do |n| - if n && (ret = n.find(usher, request, path.dup, params.dup)) + if n && (ret = n.find(usher, request, original_path, path.dup, params.dup, position)) return ret end end elsif path.size.zero? && terminates? Response.new(terminates, params) + elsif !path.size.zero? && (greedy? && ((next_path, matched_part) = greedy_lookup.match_with_result(whole_path = original_path[position, original_path.size]))) + position += matched_part.size + params << [next_path.value.name, whole_path.slice!(0, matched_part.size)] + next_path.find(usher, request, original_path, whole_path.size.zero? ? whole_path : usher.splitter.url_split(whole_path), params, position) elsif !path.size.zero? && (next_part = lookup[part = path.shift] || lookup[nil]) + position += part.size case next_part.value when Route::Variable case next_part.value.type when :* params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name loop do - if (next_part.value.look_ahead === part || (!usher.splitter.delimiter_chars.include?(part[0]) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part))) + if (next_part.value.look_ahead === part || (!usher.delimiter_chars.include?(part[0]) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part))) path.unshift(part) - path.unshift(next_part.parent.value) if usher.splitter.delimiter_chars.include?(next_part.parent.value[0]) + position -= part.size + if usher.delimiter_chars.include?(next_part.parent.value[0]) + path.unshift(next_part.parent.value) + position -= next_part.parent.value.size + end break elsif next_part.value.globs_capture_separators params.last.last << part - elsif !usher.splitter.delimiter_chars.include?(part[0]) + elsif !usher.delimiter_chars.include?(part[0]) next_part.value.valid!(part) params.last.last << part end if path.size.zero? break @@ -122,14 +153,16 @@ when :':' var = next_part.value var.valid!(part) params << [var.name, part] until (var.look_ahead === path.first) || path.empty? - params.last.last << path.shift + next_path_part = path.shift + position += next_path_part.size + params.last.last << next_path_part end end end - next_part.find(usher, request, path, params) + next_part.find(usher, request, original_path, path, params, position) else nil end end