From 6569d1b0fd483f44e37fe0d7f56e394deb3e579e Mon Sep 17 00:00:00 2001 From: Brandon Dimcheff Date: Wed, 28 Jan 2009 15:27:32 -0500 Subject: [PATCH] Added route block params in routing statements [#140] --- README.rdoc | 12 ++++++ lib/sinatra/base.rb | 3 +- test/helper.rb | 8 ++++ test/routing_test.rb | 100 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 926bcdba..420df373 100644 --- a/README.rdoc +++ b/README.rdoc @@ -50,6 +50,12 @@ Route patterns may include named parameters, accessible via the "Hello #{params[:name]}!" end +You can also access named parameters via block parameters: + + get '/hello/:name' do |n| + "Hello #{n}!" + end + Route patterns may also include splat (or wildcard) parameters, accessible via the params[:splat] array. @@ -69,6 +75,12 @@ Route matching with Regular Expressions: "Hello, #{params[:captures].first}!" end +Or with a block parameter: + + get %r{/hello/([\w]+)} do |c| + "Hello, #{c}!" + end + Routes may include a variety of matching conditions, such as the user agent: get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 9e931aa9..26e5b4d5 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -377,6 +377,7 @@ module Sinatra {} end @params = original_params.merge(params) + @block_params = values catch(:pass) do conditions.each { |cond| @@ -641,7 +642,7 @@ module Sinatra define_method "#{verb} #{path}", &block unbound_method = instance_method("#{verb} #{path}") - block = lambda { unbound_method.bind(self).call } + block = lambda { unbound_method.bind(self).call(*@block_params) } (routes[verb] ||= []). push([pattern, keys, conditions, block]).last diff --git a/test/helper.rb b/test/helper.rb index 0fa28b72..f6d202f4 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -42,3 +42,11 @@ def describe(*args, &block) end klass.class_eval &block end + +# Do not output warnings for the duration of the block. +def silence_warnings + $VERBOSE, v = nil, $VERBOSE + yield +ensure + $VERBOSE = v +end diff --git a/test/routing_test.rb b/test/routing_test.rb index e8c472b7..e9d7228c 100644 --- a/test/routing_test.rb +++ b/test/routing_test.rb @@ -498,4 +498,104 @@ describe "Routing" do assert ok? assert_equal 'default', body end + + it 'passes a single url param as block parameters when one param is specified' do + mock_app { + get '/:foo' do |foo| + assert_equal 'bar', foo + end + } + + get '/bar' + end + + it 'passes multiple params as block parameters when many are specified' do + mock_app { + get '/:foo/:bar/:baz' do |foo, bar, baz| + assert_equal 'abc', foo + assert_equal 'def', bar + assert_equal 'ghi', baz + end + } + + get '/abc/def/ghi' + end + + it 'passes regular expression captures as block parameters' do + mock_app { + get(/^\/fo(.*)\/ba(.*)/) do |foo, bar| + assert_equal 'orooomma', foo + assert_equal 'f', bar + end + } + + get '/foorooomma/baf' + end + + it "supports mixing multiple splat params like /*/foo/*/* as block parameters" do + mock_app { + get '/*/foo/*/*' do |foo, bar, baz| + assert_equal 'bar', foo + assert_equal 'bling', bar + assert_equal 'baz/boom', baz + end + } + + get '/bar/foo/bling/baz/boom' + end + + it 'raises an ArgumentError if there are too few block parameters' do + mock_app { + get '/:foo/:bar/:baz' do |foo, bar| + 'quux' + end + } + + assert_raise(ArgumentError) { get '/a/b/c' } + end + + it 'does not raise an ArgumentError with fewer block params defined then given in route' do + mock_app { + get '/:foo/:bar/:baz' do |foo| + 'quux' + end + } + + silence_warnings do + assert_nothing_raised { get '/a/b/c' } + end + end + + it 'raises an ArgumentError with more block params defined then given' do + mock_app { + get '/:foo/:bar' do |foo, bar, baz| + 'quux' + end + } + + assert_raise(ArgumentError) { get '/a/b' } + end + + it 'raises an ArgumentError if there are too many block parameters when there are no captures' do + mock_app { + get '/foo' do |foo| + 'quux' + end + } + + silence_warnings do + assert_nothing_raised { get '/foo' } + end + end + + it 'succeeds if no block parameters are specified' do + mock_app { + get '/:foo/:bar' do + 'quux' + end + } + + assert_nothing_raised { get '/a/b' } + assert_equal 'quux', body + end end