0
0
Fork 0

sort routes for more specific results

This change sorts the routes to get the most specific routes first and
avoid hitting a route which is not the most specific match.
With this the regex to extract variables is made more strict to avoid
matching half of the URI.
This commit is contained in:
Gibheer 2013-09-09 15:45:59 +02:00
parent c55441f990
commit defb7703c6
2 changed files with 33 additions and 2 deletions

View File

@ -20,7 +20,7 @@ module Zero
# match for variables in routes
VARIABLE_MATCH = %r{:(\w+)[^/]?}
# the replacement string to make it an regex
VARIABLE_REGEX = '(?<\1>.+?)'
VARIABLE_REGEX = '(?<\1>[\w]+?)'
# regex part of the beginning of the line
REGEX_BEGINNING = '\A'
# regex part of the end of the line
@ -41,7 +41,7 @@ module Zero
# @param routes [Hash] a map of URLs to rack compatible applications
def initialize(routes)
@routes = {}
routes.each do |route, target|
routes.to_a.sort_by(&:first).reverse.each do |route, target|
@routes[
Regexp.new(REGEX_BEGINNING +
route.gsub(VARIABLE_MATCH, VARIABLE_REGEX) +

View File

@ -44,6 +44,22 @@ describe Zero::Router, '#call' do
it_behaves_like "a sample app"
end
context 'with nested variable routes' do
let(:routes) do
{ '/' => wrong_app, '/foo/:id' => app, '/foo/:id/bar' => wrong_app }
end
let(:env) { EnvGenerator.get('/foo/23') }
it_behaves_like "a sample app"
end
context 'with nested routes and variable in the middle' do
let(:routes) do
{ '/' => wrong_app, '/foo/:id' => wrong_app, '/foo/:id/bar' => app }
end
let(:env) { EnvGenerator.get('/foo/23/bar') }
it_behaves_like "a sample app"
end
context 'with a route not found' do
let(:routes) {{ '/foo' => wrong_app, '/foo/bar/baz' => app }}
let(:env) { EnvGenerator.get('/foo/bar') }
@ -72,4 +88,19 @@ describe Zero::Router, '#call' do
it_behaves_like 'a sample app'
end
context 'with parameters and nested routes' do
let(:routes) do
{ '/' => wrong_app, '/foo/:id' => app, '/foo/:id/bar' => wrong_app }
end
let(:env) { EnvGenerator.get('/foo/bar') }
let(:app) do
lambda do |env|
[200, content_type, [Zero::Request.new(env).params['id']]]
end
end
let(:result) { ['bar'] }
it_behaves_like "a sample app"
end
end