Skip to content

Commit be893af

Browse files
committed
Merge pull request #251 from simulacre/nested_namespace_validators
changes: nested namespaces enforce their and parent validations; adds HashStack#gather
2 parents 03fe2d5 + c72c66f commit be893af

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

lib/grape/endpoint.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ def run(env)
295295

296296
run_filters befores
297297

298-
Array(settings[:validations]).each do |validator|
298+
# Retieve validations from this namespace and all parent namespaces.
299+
settings.gather(:validations).each do |validator|
299300
validator.validate!(params)
300301
end
301302

lib/grape/util/hash_stack.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def peek
1818
end
1919

2020
# Add a new hash to the top of the stack.
21-
#
21+
#
2222
# @param hash [Hash] optional hash to be pushed. Defaults to empty hash
2323
# @return [HashStack]
2424
def push(hash = {})
@@ -31,7 +31,7 @@ def pop
3131
end
3232

3333
# Looks through the stack for the first frame that matches :key
34-
#
34+
#
3535
# @param key [Symbol] key to look for in hash frames
3636
# @return value of given key after merging the stack
3737
def get(key)
@@ -52,7 +52,7 @@ def set(key, value)
5252
alias_method :[]=, :set
5353

5454
# Replace multiple values on the top hash of the stack.
55-
#
55+
#
5656
# @param hash [Hash] Hash of values to be merged in.
5757
def update(hash)
5858
peek.merge!(hash)
@@ -83,6 +83,15 @@ def concat(hash_stack)
8383
self
8484
end
8585

86+
# Looks through the stack for all instances of a given key and returns
87+
# them as a flat Array.
88+
#
89+
# @param key [Symbol] The key to gather
90+
# @return [Array]
91+
def gather(key)
92+
stack.map{|s| s[key] }.flatten.compact.uniq
93+
end
94+
8695
def to_s
8796
@stack.to_s
8897
end

spec/grape/validations_spec.rb

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,20 @@ def app; subject end
4949
end
5050

5151
context 'custom validation' do
52-
module CustomValidations
52+
module CustomValidations
5353
class Customvalidator < Grape::Validations::Validator
5454
def validate_param!(attr_name, params)
5555
unless params[attr_name] == 'im custom'
5656
throw :error, :status => 400, :message => "#{attr_name}: is not custom!"
57-
end
57+
end
5858
end
59-
end
60-
end
59+
end
60+
end
6161

6262
context 'when using optional with a custom validator' do
6363
before do
6464
subject.params { optional :custom, :customvalidator => true }
65-
subject.get '/optional_custom' do 'optional with custom works!'; end
65+
subject.get '/optional_custom' do 'optional with custom works!'; end
6666
end
6767

6868
it 'validates when param is present' do
@@ -83,7 +83,7 @@ def validate_param!(attr_name, params)
8383

8484
it 'validates with custom validator when param present and incorrect type' do
8585
subject.params { optional :custom, :type => String, :customvalidator => true }
86-
86+
8787
get '/optional_custom', { :custom => 123 }
8888
last_response.status.should == 400
8989
last_response.body.should == 'custom: is not custom!'
@@ -111,6 +111,44 @@ def validate_param!(attr_name, params)
111111
last_response.status.should == 400
112112
last_response.body.should == 'missing parameter: custom'
113113
end
114+
115+
context 'nested namespaces' do
116+
before do
117+
subject.params { requires :custom, :customvalidator => true }
118+
subject.namespace 'nested' do
119+
get 'one' do 'validation failed' end
120+
namespace 'nested' do
121+
get 'two' do 'validation failed' end
122+
end
123+
end
124+
subject.namespace 'peer' do
125+
get 'one' do 'no validation required' end
126+
namespace 'nested' do
127+
get 'two' do 'no validation required' end
128+
end
129+
end
130+
end
131+
specify 'the parent namespace should use the validator' do
132+
get '/nested/one', { :custom => 'im wrong, validate me'}
133+
last_response.status.should == 400
134+
last_response.body.should == 'custom: is not custom!'
135+
end
136+
specify 'the nested namesapce should inherit the custom validator' do
137+
get '/nested/nested/two', { :custom => 'im wrong, validate me'}
138+
last_response.status.should == 400
139+
last_response.body.should == 'custom: is not custom!'
140+
end
141+
specify 'peer namesapces should not have the validator' do
142+
get '/peer/one', { :custom => 'im not validated' }
143+
last_response.status.should == 200
144+
last_response.body.should == 'no validation required'
145+
end
146+
specify 'namespaces nested in peers should also not have the validator' do
147+
get '/peer/nested/two', { :custom => 'im not validated' }
148+
last_response.status.should == 200
149+
last_response.body.should == 'no validation required'
150+
end
151+
end
114152
end
115153
end # end custom validation
116154
end

0 commit comments

Comments
 (0)