require File.join('usher', 'node', 'root') require File.join('usher', 'node', 'response') class Usher class Node attr_reader :normal, :greedy, :request attr_accessor :terminates, :request_method_type, :parent, :value, :request_methods def initialize(parent, value) @parent, @value = parent, value end def depth @depth ||= parent.is_a?(Node) ? parent.depth + 1 : 0 end def terminates? @terminates && @terminates.route.recognizable? end def ancestors unless @ancestors @ancestors = [] node = self while (node.respond_to?(:parent)) @ancestors << node node = node.parent end end @ancestors end def root @root ||= ancestors.last end def route_set @route_set ||= root.route_set end def inspect out = '' out << " " * depth out << "#{terminates? ? '* ' : ''}#{depth}: #{value.inspect}\n" [:normal, :greedy, :request].each do |node_type| send(node_type).each do |k,v| out << (" " * (depth + 1)) << "#{node_type.to_s[0].chr} #{k.inspect} ==> \n" << v.inspect end if send(node_type) end out end def find(request_object, original_path, path, params = []) # terminates or is partial if terminates? && (path.empty? || terminates.route.partial_match?) response = terminates.route.partial_match? ? Response.new(terminates, params, path.join, original_path[0, original_path.size - path.join.size]) : Response.new(terminates, params, nil, original_path) # terminates or is partial elsif !path.empty? and greedy and match_with_result_output = greedy.match_with_result(whole_path = path.join) child_node, matched_part = match_with_result_output whole_path.slice!(0, matched_part.size) params << matched_part if child_node.value.is_a?(Route::Variable) child_node.find(request_object, original_path, whole_path.empty? ? whole_path : route_set.splitter.split(whole_path), params) elsif !path.empty? and normal and child_node = normal[path.first] || normal[nil] part = path.shift case child_node.value when String when Route::Variable::Single variable = child_node.value # get the variable variable.valid!(part) # do a validity check until path.empty? || (variable.look_ahead === path.first) # variables have a look ahead notion, next_path_part = path.shift # and until they are satified, part << next_path_part end if variable.look_ahead params << part # because its a variable, we need to add it to the params array when Route::Variable::Glob params << [] loop do if (child_node.value.look_ahead === part || (!route_set.delimiters.unescaped.include?(part) && child_node.value.regex_matcher && !child_node.value.regex_matcher.match(part))) path.unshift(part) path.unshift(child_node.parent.value) if route_set.delimiters.unescaped.include?(child_node.parent.value) break elsif !route_set.delimiters.unescaped.include?(part) child_node.value.valid!(part) params.last << part end unless part = path.shift break end end end child_node.find(request_object, original_path, path, params) elsif request_method_type if route_set.priority_lookups? route_candidates = [] if specific_node = request[request_object.send(request_method_type)] and ret = specific_node.find(request_object, original_path, path.dup, params && params.dup) route_candidates << ret end if general_node = request[nil] and ret = general_node.find(request_object, original_path, path.dup, params && params.dup) route_candidates << ret end route_candidates.sort!{|r1, r2| r1.path.route.priority <=> r2.path.route.priority} route_candidates.last else if specific_node = request[request_object.send(request_method_type)] and ret = specific_node.find(request_object, original_path, path.dup, params && params.dup) ret elsif general_node = request[nil] and ret = general_node.find(request_object, original_path, path.dup, params && params.dup) ret end end else nil end end def activate_normal! @normal ||= {} end def activate_greedy! @greedy ||= {} end def activate_request! @request ||= {} end def upgrade_normal! @normal = FuzzyHash.new(@normal) end def upgrade_greedy! @greedy = FuzzyHash.new(@greedy) end def upgrade_request! @request = FuzzyHash.new(@request) end end end