diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
4 files changed, 79 insertions, 26 deletions
diff --git a/actionpack/lib/action_dispatch/journey/nodes/node.rb b/actionpack/lib/action_dispatch/journey/nodes/node.rb index 542e8c6577..d069bf0205 100644 --- a/actionpack/lib/action_dispatch/journey/nodes/node.rb +++ b/actionpack/lib/action_dispatch/journey/nodes/node.rb @@ -41,6 +41,7 @@ module ActionDispatch def literal?; false; end def terminal?; false; end def star?; false; end + def cat?; false; end end class Terminal < Node # :nodoc: @@ -72,11 +73,13 @@ module ActionDispatch class Symbol < Terminal # :nodoc: attr_accessor :regexp alias :symbol :regexp + attr_reader :name DEFAULT_EXP = /[^\.\/\?]+/ def initialize(left) super @regexp = DEFAULT_EXP + @name = left.tr '*:'.freeze, ''.freeze end def default_regexp? @@ -115,6 +118,7 @@ module ActionDispatch end class Cat < Binary # :nodoc: + def cat?; true; end def type; :CAT; end end diff --git a/actionpack/lib/action_dispatch/journey/route.rb b/actionpack/lib/action_dispatch/journey/route.rb index d44c3d31d7..209cd20d80 100644 --- a/actionpack/lib/action_dispatch/journey/route.rb +++ b/actionpack/lib/action_dispatch/journey/route.rb @@ -8,18 +8,61 @@ module ActionDispatch attr_accessor :precedence + module VerbMatchers + VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK } + VERBS.each do |v| + class_eval <<-eoc + class #{v} + def self.verb; name.split("::").last; end + def self.call(req); req.#{v.downcase}?; end + end + eoc + end + + class Unknown + attr_reader :verb + + def initialize(verb) + @verb = verb + end + + def call(request); @verb === request.request_method; end + end + + class All + def self.call(_); true; end + def self.verb; ''; end + end + + VERB_TO_CLASS = VERBS.each_with_object({ :all => All }) do |verb, hash| + klass = const_get verb + hash[verb] = klass + hash[verb.downcase] = klass + hash[verb.downcase.to_sym] = klass + end + + end + + def self.verb_matcher(verb) + VerbMatchers::VERB_TO_CLASS.fetch(verb) do + VerbMatchers::Unknown.new verb.to_s.dasherize.upcase + end + end + def self.build(name, app, path, constraints, required_defaults, defaults) - new name, app, path, constraints, required_defaults, defaults + request_method_match = verb_matcher(constraints.delete(:request_method)) + new name, app, path, constraints, required_defaults, defaults, request_method_match end ## # +path+ is a path constraint. # +constraints+ is a hash of constraints to be applied to this route. - def initialize(name, app, path, constraints, required_defaults, defaults) + def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match) @name = name @app = app @path = path + @request_method_match = request_method_match @constraints = constraints @defaults = defaults @required_defaults = nil @@ -96,7 +139,8 @@ module ActionDispatch end def matches?(request) - constraints.all? do |method, value| + match_verb(request) && + constraints.all? { |method, value| case value when Regexp, String value === request.send(method).to_s @@ -109,7 +153,7 @@ module ActionDispatch else value === request.send(method) end - end + } end def ip @@ -117,11 +161,20 @@ module ActionDispatch end def requires_matching_verb? - constraints[:request_method] + !@request_method_match.all? { |x| x == VerbMatchers::All } end def verb - constraints[:request_method] || // + %r[^#{verbs.join('|')}$] + end + + private + def verbs + @request_method_match.map(&:verb) + end + + def match_verb(request) + @request_method_match.any? { |m| m.call request } end end end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index e964bf59e0..c1134d16ad 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -144,12 +144,13 @@ module ActionDispatch end def make_route(name, precedence) - route = Journey::Route.build(name, + route = Journey::Route.new(name, application, path, conditions, required_defaults, - defaults) + defaults, + request_method) route.precedence = precedence route @@ -170,38 +171,32 @@ module ActionDispatch def build_conditions(current_conditions, request_class) conditions = current_conditions.dup - # Rack-Mount requires that :request_method be a regular expression. - # :request_method represents the HTTP verb that matches this route. - # - # Here we munge values before they get sent on to rack-mount. - unless @via == [:all] - verbs = @via.map { |m| m.to_s.dasherize.upcase } - conditions[:request_method] = %r[^#{verbs.join('|')}$] - end - conditions.keep_if do |k, _| request_class.public_method_defined?(k) end end private :build_conditions + def request_method + @via.map { |x| Journey::Route.verb_matcher(x) } + end + private :request_method + JOINED_SEPARATORS = SEPARATORS.join # :nodoc: def build_path(ast, requirements, anchor) pattern = Journey::Path::Pattern.new(ast, requirements, JOINED_SEPARATORS, anchor) - builder = Journey::GTG::Builder.new ast - # Get all the symbol nodes followed by literals that are not the # dummy node. - symbols = ast.grep(Journey::Nodes::Symbol).find_all { |n| - builder.followpos(n).first.literal? - } + symbols = ast.find_all { |n| + n.cat? && n.left.symbol? && n.right.cat? && n.right.left.literal? + }.map(&:left) # Get all the symbol nodes preceded by literals. - symbols.concat ast.find_all(&:literal?).map { |n| - builder.followpos(n).first - }.find_all(&:symbol?) + symbols.concat ast.find_all { |n| + n.cat? && n.left.literal? && n.right.cat? && n.right.left.symbol? + }.map { |n| n.right.left } symbols.each { |x| x.regexp = /(?:#{Regexp.union(x.regexp, '-')})+/ @@ -640,7 +635,7 @@ module ActionDispatch # Query if the following named route was already defined. def has_named_route?(name) - @set.named_routes.routes[name.to_sym] + @set.named_routes.key? name end private diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 30e308119d..20926012b4 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -89,6 +89,7 @@ module ActionDispatch class NamedRouteCollection include Enumerable attr_reader :routes, :url_helpers_module, :path_helpers_module + private :routes def initialize @routes = {} |