diff --git a/sinatra-contrib/README.md b/sinatra-contrib/README.md index 4fb5b5e5..18fb3ae5 100644 --- a/sinatra-contrib/README.md +++ b/sinatra-contrib/README.md @@ -39,6 +39,9 @@ Currently included: corresponding `Link` HTTP headers. Adds `link`, `stylesheet` and `prefetch` helper methods. +* `sinatra/multi_route`: Adds ability to define one route block for multiple + routes and multiple or custom HTTP verbs. + * `sinatra/namespace`: Adds namespace support to Sinatra. * `sinatra/respond_with`: Choose action and/or template depending automatically diff --git a/sinatra-contrib/lib/sinatra/contrib.rb b/sinatra-contrib/lib/sinatra/contrib.rb index 47a8e305..332447d7 100644 --- a/sinatra-contrib/lib/sinatra/contrib.rb +++ b/sinatra-contrib/lib/sinatra/contrib.rb @@ -8,6 +8,7 @@ module Sinatra # Sinatra::Application by default. module Common register :ConfigFile + register :MultiRoute register :Namespace register :RespondWith diff --git a/sinatra-contrib/lib/sinatra/multi_route.rb b/sinatra-contrib/lib/sinatra/multi_route.rb new file mode 100644 index 00000000..9a9f2ec1 --- /dev/null +++ b/sinatra-contrib/lib/sinatra/multi_route.rb @@ -0,0 +1,81 @@ +require 'sinatra/base' + +module Sinatra + # = Sinatra::MultiRoute + # + # Create multiple routes with one statement. + # + # == Usage + # + # Use this extension to create a handler for multiple routes: + # + # get '/foo', '/bar' do + # # ... + # end + # + # Or for multiple verbs: + # + # route :get, :post, '/' do + # # ... + # end + # + # Or even for custom verbs: + # + # route 'LIST', '/' do + # # ... + # end + # + # === Classic Application + # + # To use the extension in a classic application all you need to do is require + # it: + # + # require "sinatra" + # require "sinatra/multi_route" + # + # # Your classic application code goes here... + # + # === Modular Application + # + # To use the extension in a modular application you need to require it, and + # then, tell the application you will use it: + # + # require "sinatra/base" + # require "sinatra/multi_route" + # + # class MyApp < Sinatra::Base + # register Sinatra::MultiRoute + # + # # The rest of your modular application code goes here... + # end + # + module MultiRoute + def head(*args, &block) super(*route_args(args), &block) end + def delete(*args, &block) super(*route_args(args), &block) end + def get(*args, &block) super(*route_args(args), &block) end + def options(*args, &block) super(*route_args(args), &block) end + def patch(*args, &block) super(*route_args(args), &block) end + def post(*args, &block) super(*route_args(args), &block) end + def put(*args, &block) super(*route_args(args), &block) end + + def route(*args, &block) + options = Hash === args.last ? args.pop : {} + routes = [*args.pop] + args.each do |verb| + verb = verb.to_s.upcase if Symbol === verb + routes.each do |route| + super(verb, route, options, &block) + end + end + end + + private + + def route_args(args) + options = Hash === args.last ? args.pop : {} + [args, options] + end + end + + register MultiRoute +end diff --git a/sinatra-contrib/lib/sinatra/reloader.rb b/sinatra-contrib/lib/sinatra/reloader.rb index 94672641..5020b3dc 100644 --- a/sinatra-contrib/lib/sinatra/reloader.rb +++ b/sinatra-contrib/lib/sinatra/reloader.rb @@ -234,7 +234,10 @@ module Sinatra # Does everything Sinatra::Base#route does, but it also tells the # +Watcher::List+ for the Sinatra application to watch the defined # route. - def route(verb, path, options={}, &block) + # + # Note: We are using #compile! so we don't interfere with extensions + # changing #route. + def compile!(verb, path, block, options = {}) source_location = block.respond_to?(:source_location) ? block.source_location.first : caller_files[1] signature = super diff --git a/sinatra-contrib/spec/multi_route_spec.rb b/sinatra-contrib/spec/multi_route_spec.rb new file mode 100644 index 00000000..489da2ee --- /dev/null +++ b/sinatra-contrib/spec/multi_route_spec.rb @@ -0,0 +1,45 @@ +require 'backports' +require_relative 'spec_helper' + +describe Sinatra::MultiRoute do + before do + count = 0 + mock_app do + set(:some_condition) { count += 1 } + register Sinatra::MultiRoute + get('/') { 'normal' } + get('/foo', '/bar', :some_condition => true) { 'paths' } + route('PUT', 'POST', '/') { 'verb' } + route(:get, '/baz') { 'symbol as verb' } + end + @count = count + end + + it 'does still allow normal routing' do + get('/').should be_ok + body.should be == 'normal' + end + + it 'supports multpile routes' do + get('/foo').should be_ok + body.should be == 'paths' + get('/bar').should be_ok + body.should be == 'paths' + end + + it 'triggers conditions' do + @count.should be == 4 + end + + it 'supports multpile verbs' do + post('/').should be_ok + body.should be == 'verb' + put('/').should be_ok + body.should be == 'verb' + end + + it 'takes symbols as verbs' do + get('/baz').should be_ok + body.should be == 'symbol as verb' + end +end \ No newline at end of file