make URL params available in filters with pattern.

Previously this was the only way to access parameters from pattern:

    before /:name do |name|
      ...
    end

Now it is also possible to use params:

    before /:name do
      do_something params[:name]
    end
This commit is contained in:
Konstantin Haase 2010-09-03 23:19:20 +02:00
parent 2233cdbf68
commit 739b6ba012
2 changed files with 68 additions and 45 deletions

View File

@ -494,51 +494,19 @@ module Sinatra
# Run routes defined on the class and all superclasses.
def route!(base=self.class, pass_block=nil)
if routes = base.routes[@request.request_method]
original_params = @params
path = unescape(@request.path_info)
path = "/" if path.empty?
routes.each do |pattern, keys, conditions, block|
if match = pattern.match(path)
values = match.captures.to_a
params =
if keys.any?
keys.zip(values).inject({}) do |hash,(k,v)|
if k == 'splat'
(hash[k] ||= []) << v
else
hash[k] = v
end
hash
end
elsif values.any?
{'captures' => values}
else
{}
end
@params = original_params.merge(params)
@block_params = values
pass_block = catch(:pass) do
conditions.each { |cond|
throw :pass if instance_eval(&cond) == false }
route_eval(&block)
end
pass_block = process_route(pattern, keys, conditions) do
route_eval(&block)
end
end
@params = original_params
end
# Run routes defined in superclass.
if base.superclass.respond_to?(:routes)
route! base.superclass, pass_block
return
return route!(base.superclass, pass_block)
end
route_eval(&pass_block) if pass_block
route_missing
end
@ -547,6 +515,46 @@ module Sinatra
throw :halt, instance_eval(&block)
end
# If the current request matches pattern and conditions, fill params
# with keys and call the given block.
# Revert params afterwards.
#
# Returns pass block.
def process_route(pattern, keys, conditions)
@original_params ||= @params
@path ||= begin
path = unescape(@request.path_info)
path.empty? ? "/" : path
end
if match = pattern.match(@path)
values = match.captures.to_a
params =
if keys.any?
keys.zip(values).inject({}) do |hash,(k,v)|
if k == 'splat'
(hash[k] ||= []) << v
else
hash[k] = v
end
hash
end
elsif values.any?
{'captures' => values}
else
{}
end
@params = @original_params.merge(params)
@block_params = values
catch(:pass) do
conditions.each { |cond|
throw :pass if instance_eval(&cond) == false }
yield
end
end
ensure
@params = @original_params
end
# No matching route was found or all routes passed. The default
# implementation is to forward the request downstream when running
# as middleware (@app is non-nil); when no downstream app is set, raise
@ -828,11 +836,9 @@ module Sinatra
# add a filter
def add_filter(type, path = nil, &block)
return filters[type] << block unless path
block, pattern = compile!(type, path, block)
block, *arguments = compile!(type, path, block)
add_filter(type) do
next unless match = pattern.match(request.path_info)
@block_params = match.captures.to_a
instance_eval(&block)
process_route(*arguments) { instance_eval(&block) }
end
end
@ -896,8 +902,7 @@ module Sinatra
host_name(options.delete(:host)) if options.key?(:host)
options.each { |option, args| send(option, *args) }
block, pattern, keys = compile! verb, path, block
conditions, @conditions = @conditions, []
block, pattern, keys, conditions = compile! verb, path, block
invoke_hook(:route_added, verb, path, block)
(@routes[verb] ||= []).
@ -910,12 +915,17 @@ module Sinatra
def compile!(verb, path, block)
method_name = "#{verb} #{path}"
define_method(method_name, &block)
unbound_method = instance_method method_name
unbound_method = instance_method method_name
pattern, keys = compile(path)
conditions, @conditions = @conditions, []
remove_method method_name
[block.arity != 0 ?
proc { unbound_method.bind(self).call(*@block_params) } :
proc { unbound_method.bind(self).call }, *compile(path)]
[ block.arity != 0 ?
proc { unbound_method.bind(self).call(*@block_params) } :
proc { unbound_method.bind(self).call },
pattern, keys, conditions ]
end
def compile(path)

View File

@ -264,4 +264,17 @@ class AfterFilterTest < Test::Unit::TestCase
get '/foo/bar'
assert_equal subpath, 'bar'
end
it 'is possible to access url params from the route param' do
ran = false
mock_app do
get('/foo/*') { }
before('/foo/:sub') do
assert_equal params[:sub], 'bar'
ran = true
end
end
get '/foo/bar'
assert ran
end
end