Skip to content

Commit 86574eb

Browse files
Add possibility for namespace parameters.
Specific method options (parameters and description) are now merged with the namespace parameters. So you can do something like below, and the serial parameter will be described for all methods in the namespace: ``` desc 'description', :params => { "serial" => { :desc => "Serial of requested object." } } segment '/:serial' do desc "Get details on specific object" get do present object, with: API::Entities::Object end desc "Reserve an object" post '/reserve' do present object.reserve, with: API::Entities::ObjectReserved end end ```
1 parent e03b371 commit 86574eb

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

lib/grape/api.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'rack/auth/basic'
33
require 'rack/auth/digest/md5'
44
require 'logger'
5+
require 'grape/util/deep_merge'
56

67
module Grape
78
# The API class is the primary entry point for
@@ -287,7 +288,7 @@ def route(methods, paths = ['/'], route_options = {}, &block)
287288
endpoint_options = {
288289
:method => methods,
289290
:path => paths,
290-
:route_options => (route_options || {}).merge(@last_description || {})
291+
:route_options => (@namespace_description || {}).deep_merge(@last_description || {}).deep_merge(route_options || {})
291292
}
292293
endpoints << Grape::Endpoint.new(settings.clone, endpoint_options, &block)
293294

@@ -313,9 +314,13 @@ def patch(paths = ['/'], options = {}, &block); route('PATCH', paths, options, &
313314

314315
def namespace(space = nil, &block)
315316
if space || block_given?
317+
previous_namespace_description = @namespace_description
318+
@namespace_description = (@namespace_description || {}).deep_merge(@last_description || {})
319+
@last_description = nil
316320
nest(block) do
317321
set(:namespace, space.to_s) if space
318322
end
323+
@namespace_description = previous_namespace_description
319324
else
320325
Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace]}.join('/'))
321326
end

lib/grape/util/deep_merge.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class Hash
2+
# deep_merge from rails
3+
# activesupport/lib/active_support/core_ext/hash/deep_merge.rb
4+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
5+
#
6+
# h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
7+
# h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
8+
#
9+
# h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
10+
# h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
11+
def deep_merge(other_hash)
12+
dup.deep_merge!(other_hash)
13+
end
14+
15+
# Same as +deep_merge+, but modifies +self+.
16+
def deep_merge!(other_hash)
17+
other_hash.each_pair do |k,v|
18+
tv = self[k]
19+
self[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge(v) : v
20+
end
21+
self
22+
end
23+
end

spec/grape/api_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,33 @@ def three
923923
{ :description => "Reverses a string.", :params => { "s" => { :desc => "string to reverse", :type => "string" } } }
924924
]
925925
end
926+
it "should merge the options of the namespace with the options of the method" do
927+
subject.desc "namespace", :params => { :ns_param => "ns param" }
928+
subject.namespace "ns" do
929+
desc "method", :params => { :method_param => "method param" }
930+
get "method" do ; end
931+
end
932+
subject.routes.map { |route|
933+
{ :description => route.route_description, :params => route.route_params }
934+
}.should eq [
935+
{ :description => "method", :params => { :ns_param => "ns param", :method_param => "method param" } }
936+
]
937+
end
938+
it "should merge the options of nested namespaces" do
939+
subject.desc "ns1", :params => { :ns_param => "ns param 1", :ns1_param => "ns1 param" }
940+
subject.namespace "ns1" do
941+
desc "ns2", :params => { :ns_param => "ns param 2", :ns2_param => "ns2 param" }
942+
namespace "ns2" do
943+
desc "method", :params => { :method_param => "method param" }
944+
get "method" do ; end
945+
end
946+
end
947+
subject.routes.map { |route|
948+
{ :description => route.route_description, :params => route.route_params }
949+
}.should eq [
950+
{ :description => "method", :params => { :ns_param => "ns param 2", :ns1_param => "ns1 param", :ns2_param => "ns2 param", :method_param => "method param" } }
951+
]
952+
end
926953
it "should not symbolize params" do
927954
subject.desc "Reverses a string.", { :params =>
928955
{ "s" => { :desc => "string to reverse", :type => "string" }}

0 commit comments

Comments
 (0)