From 6c60b4ccbe664621c61fda1e4f937ce28473fac3 Mon Sep 17 00:00:00 2001 From: Michael Bleigh Date: Fri, 2 Sep 2011 16:06:05 -0300 Subject: [PATCH] References #60. Adds mount class method to mount bare Rack apps. Next up, inheritable settings. --- lib/grape/api.rb | 33 +++++++++++++++++++++++++-------- spec/grape/api_spec.rb | 30 +++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/lib/grape/api.rb b/lib/grape/api.rb index 3b12a9046d..c2877e55d4 100644 --- a/lib/grape/api.rb +++ b/lib/grape/api.rb @@ -51,6 +51,11 @@ def settings_stack def set(key, value) @settings.last[key.to_sym] = value end + + # Merge multiple setting in at once. Mostly for internal use. + def merge_settings(settings) + settings_stack.last.merge!(settings) + end # Define a root URL prefix for your entire # API. @@ -180,6 +185,15 @@ def http_digest(options = {}, &block) auth :http_digest, options, &block end + def mount(mounts) + mounts.each_pair do |app, path| + next unless app.respond_to?(:call) + route_set.add_route(app, + path_info: compile_path(path, false) + ) + end + end + # Defines a route that will be recognized # by the Grape API. # @@ -200,16 +214,12 @@ def route(methods, paths = ['/'], route_options = {}, &block) endpoint = build_endpoint(&block) - endpoint_options = {} - endpoint_options[:version] = /#{version.join('|')}/ if version - route_options ||= {} methods.each do |method| paths.each do |path| - - compiled_path = compile_path(path) - path = Rack::Mount::Strexp.compile(compiled_path, endpoint_options, %w( / . ? ), true) + prepared_path = prepare_path(path) + path = compile_path(path) regex = Rack::Mount::RegexpWithNamedGroups.new(path) path_params = regex.named_captures.map { |nc| nc[0] } - [ 'version', 'format' ] path_params |= (route_options[:params] || []) @@ -220,7 +230,7 @@ def route(methods, paths = ['/'], route_options = {}, &block) :version => version ? version.join('|') : nil, :namespace => namespace, :method => request_method, - :path => compiled_path, + :path => prepared_path, :params => path_params})) route_set.add_route(endpoint, @@ -352,7 +362,7 @@ def route_set @route_set ||= Rack::Mount::RouteSet.new end - def compile_path(path) + def prepare_path(path) parts = [] parts << prefix if prefix parts << ':version' if version @@ -361,6 +371,13 @@ def compile_path(path) parts.last << '(.:format)' Rack::Mount::Utils.normalize_path(parts.join('/')) end + + def compile_path(path, anchor = true) + endpoint_options = {} + endpoint_options[:version] = /#{version.join('|')}/ if version + + Rack::Mount::Strexp.compile(prepare_path(path), endpoint_options, %w( / . ? ), anchor) + end end reset! diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 619f78d15d..8d48b0ec98 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -113,7 +113,7 @@ def app; subject end subject.version :v1 subject.namespace :awesome do - compile_path('hello').should == '/rad/:version/awesome/hello(.:format)' + prepare_path('hello').should == '/rad/:version/awesome/hello(.:format)' end end @@ -151,9 +151,9 @@ def app; subject end it 'should be callable with nil just to push onto the stack' do subject.namespace do version 'v2' - compile_path('hello').should == '/:version/hello(.:format)' + prepare_path('hello').should == '/:version/hello(.:format)' end - subject.send(:compile_path, 'hello').should == '/hello(.:format)' + subject.send(:prepare_path, 'hello').should == '/hello(.:format)' end %w(group resource resources segment).each do |als| @@ -755,4 +755,28 @@ class CommunicationError < RuntimeError; end end end + describe '#settings=' do + it 'should set the last settings on the stack' do + subject.merge_settings :biff => 'bap' + subject.settings[:biff].should == 'bap' + end + end + + describe '.mount.' do + context 'with a bare rack app' do + before do + subject.mount lambda{|env| [200, {}, ["MOUNTED"]]} => '/mounty' + end + + it 'should make a bare Rack app available at the endpoint' do + get '/mounty' + last_response.body.should == 'MOUNTED' + end + + it 'should anchor the routes, passing all subroutes to it' do + get '/mounty/awesome' + last_response.body.should == 'MOUNTED' + end + end + end end