Skip to content
Browse files

add route to public api, let route accept multiple verbs at once

  • Loading branch information...
1 parent 501c3c3 commit 46a6c17788c3adb0c7f2c0149c05f630e0132b44 @rkh rkh committed Apr 27, 2011
Showing with 187 additions and 18 deletions.
  1. +4 −0 CHANGES
  2. +21 −0 README.rdoc
  3. +13 −12 lib/sinatra/base.rb
  4. +13 −0 test/delegator_test.rb
  5. +136 −6 test/routing_test.rb
View
4 CHANGES
@@ -2,6 +2,10 @@
* Added support for HTTP PATCH requests. (Konstantin Haase)
+ * The route method is now part of the public API and also takes multiple
+ verbs as arguments, allowing you to define routes for multiple and/or
+ custom HTTP methods in one short statement. (Rick Olson, Konstantin Haase)
+
* Support for Creole templates, Creole is a standardized wiki markup,
supported by many wiki implementations. (Konstanin Haase)
View
21 README.rdoc
@@ -196,6 +196,27 @@ Or, using negative look ahead:
# ...
end
+=== Custom or Multiple HTTP Verbs
+
+Sometimes you want to use custom HTTP verbs, not supported by Sinatra out of
+the box, for instance, if you want to implement a WebDAV server. Simply use
+the +route+ method, which has nearly the same signature as the other routing
+methods, except it also takes one or more HTTP verbs as first argument:
+
+ route :list, '/foo' do
+ "You just used the LIST verb, thanks!"
+ end
+
+ route :post, :get, '/foo' do
+ "I answer both POST and GET."
+ end
+
+Just like +get+ and friends, you can use conditions:
+
+ route :list, '/:dir', :agent => /MyClient/ do
+ Dir.glob(params[:dir]).join "\n"
+ end
+
== Static Files
Static files are served from the <tt>./public</tt> directory. You can specify
View
25 lib/sinatra/base.rb
@@ -1108,11 +1108,7 @@ def provides(*types)
# Defining a `GET` handler also automatically defines
# a `HEAD` handler.
def get(path, opts={}, &block)
- conditions = @conditions.dup
- route('GET', path, opts, &block)
-
- @conditions = conditions
- route('HEAD', path, opts, &block)
+ route('GET', 'HEAD', path, opts, &block)
end
def put(path, opts={}, &bk) route 'PUT', path, opts, &bk end
@@ -1122,19 +1118,24 @@ def head(path, opts={}, &bk) route 'HEAD', path, opts, &bk end
def options(path, opts={}, &bk) route 'OPTIONS', path, opts, &bk end
def patch(path, opts={}, &bk) route 'PATCH', path, opts, &bk end
- private
- def route(verb, path, options={}, &block)
+ def route(*args, &block)
+ options = args.last.respond_to?(:to_hash) ? args.pop.to_hash : {}
+ path = args.pop
+
# Because of self.options.host
host_name(options.delete(:host)) if options.key?(:host)
enable :empty_path_info if path == "" and empty_path_info.nil?
- block, pattern, keys, conditions = compile! verb, path, block, options
- invoke_hook(:route_added, verb, path, block)
+ args.each do |verb|
+ verb = verb.to_s.upcase
+ block, pattern, keys, conditions = compile! verb, path, block, options
+ invoke_hook(:route_added, verb, path, block)
- (@routes[verb] ||= []).
- push([pattern, keys, conditions, block]).last
+ (@routes[verb] ||= []).push [pattern, keys, conditions, block]
+ end
end
+ private
def invoke_hook(name, *args)
extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
end
@@ -1498,7 +1499,7 @@ def #{method_name}(*args, &b)
delegate :get, :patch, :put, :post, :delete, :head, :options, :template, :layout,
:before, :after, :error, :not_found, :configure, :set, :mime_type,
:enable, :disable, :use, :development?, :test?, :production?,
- :helpers, :settings
+ :helpers, :settings, :route
class << self
attr_accessor :target
View
13 test/delegator_test.rb
@@ -71,6 +71,19 @@ def target
assert response.ok?
assert_equal 'Hello World', response.body
end
+
+ it "delegates route(:#{verb}) correctly" do
+ delegation_app do
+ route verb.to_sym, '/hello' do
+ 'Hello World'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request(verb.upcase, '/hello', {})
+ assert response.ok?
+ assert_equal 'Hello World', response.body
+ end
end
it "delegates head correctly" do
View
142 test/routing_test.rb
@@ -23,28 +23,113 @@ def keys
end
class RoutingTest < Test::Unit::TestCase
- %w[get put post delete options patch].each do |verb|
+ verbs = %w[get put post delete options patch]
+ verbs.each do |verb|
it "defines #{verb.upcase} request handlers with #{verb}" do
- mock_app {
+ mock_app do
send verb, '/hello' do
'Hello World'
end
- }
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request(verb.upcase, '/hello', {})
+ assert response.ok?
+ assert_equal 'Hello World', response.body
+ end
+
+ it "lets you define routes with routes(#{verb.upcase.inspect}, ...)" do
+ mock_app do
+ route verb.upcase, '/hello' do
+ 'Hello World'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request(verb.upcase, '/hello', {})
+ assert response.ok?
+ assert_equal 'Hello World', response.body
+ end
+
+ it "lets you define routes with routes(:#{verb}, ...)" do
+ mock_app do
+ route verb.to_sym, '/hello' do
+ 'Hello World'
+ end
+ end
request = Rack::MockRequest.new(@app)
response = request.request(verb.upcase, '/hello', {})
assert response.ok?
assert_equal 'Hello World', response.body
end
+
+ verbs.each do |other|
+ it "lets you define routes with routes(#{verb.upcase.inspect}, #{other.upcase.inspect}, ...)" do
+ mock_app do
+ route verb.upcase, other.upcase, '/hello' do
+ 'Hello World'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request(verb.upcase, '/hello', {})
+ assert response.ok?
+ assert_equal 'Hello World', response.body
+ end
+
+ it "lets you define routes with routes(:#{other}, :#{verb}, ...)" do
+ mock_app do
+ route other.to_sym, verb.to_sym, '/hello' do
+ 'Hello World'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request(verb.upcase, '/hello', {})
+ assert response.ok?
+ assert_equal 'Hello World', response.body
+ end
+ end
end
- it "defines HEAD request handlers with HEAD" do
- mock_app {
+ it "defines HEAD request handlers with head" do
+ mock_app do
head '/hello' do
response['X-Hello'] = 'World!'
'remove me'
end
- }
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request('HEAD', '/hello', {})
+ assert response.ok?
+ assert_equal 'World!', response['X-Hello']
+ assert_equal '', response.body
+ end
+
+ it "lets you define routes with routes('HEAD', ...)" do
+ mock_app do
+ route 'HEAD', '/hello' do
+ response['X-Hello'] = 'World!'
+ 'remove me'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request('HEAD', '/hello', {})
+ assert response.ok?
+ assert_equal 'World!', response['X-Hello']
+ assert_equal '', response.body
+ end
+
+ it "lets you define routes with routes(:head, ...)" do
+ mock_app do
+ route :head, '/hello' do
+ response['X-Hello'] = 'World!'
+ 'remove me'
+ end
+ end
request = Rack::MockRequest.new(@app)
response = request.request('HEAD', '/hello', {})
@@ -53,6 +138,51 @@ class RoutingTest < Test::Unit::TestCase
assert_equal '', response.body
end
+ verbs.each do |other|
+ it "lets you define routes with routes('HEAD', #{other.upcase.inspect}, ...)" do
+ mock_app do
+ route 'HEAD', other.upcase, '/hello' do
+ response['X-Hello'] = 'World!'
+ 'remove me'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request('HEAD', '/hello', {})
+ assert response.ok?
+ assert_equal 'World!', response['X-Hello']
+ assert_equal '', response.body
+ end
+
+ it "lets you define routes with routes(:#{other}, :head, ...)" do
+ mock_app do
+ route other.to_sym, :head, '/hello' do
+ response['X-Hello'] = 'World!'
+ 'remove me'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request('HEAD', '/hello', {})
+ assert response.ok?
+ assert_equal 'World!', response['X-Hello']
+ assert_equal '', response.body
+ end
+ end
+
+ it "lets you define routes for custom verbs" do
+ mock_app do
+ route :foo, '/hello' do
+ 'Hello World'
+ end
+ end
+
+ request = Rack::MockRequest.new(@app)
+ response = request.request("FOO", '/hello', {})
+ assert response.ok?
+ assert_equal 'Hello World', response.body
+ end
+
it "404s when no route satisfies the request" do
mock_app {
get('/foo') { }

0 comments on commit 46a6c17

Please sign in to comment.
Something went wrong with that request. Please try again.