grape 0.3.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +70 -0
  4. data/.travis.yml +7 -6
  5. data/CHANGELOG.md +134 -4
  6. data/CONTRIBUTING.md +118 -0
  7. data/Gemfile +5 -2
  8. data/README.md +551 -116
  9. data/RELEASING.md +105 -0
  10. data/Rakefile +29 -8
  11. data/UPGRADING.md +124 -0
  12. data/grape.gemspec +3 -3
  13. data/lib/grape/api.rb +207 -88
  14. data/lib/grape/cookies.rb +4 -8
  15. data/lib/grape/endpoint.rb +198 -144
  16. data/lib/grape/error_formatter/base.rb +5 -7
  17. data/lib/grape/error_formatter/json.rb +3 -5
  18. data/lib/grape/error_formatter/txt.rb +1 -3
  19. data/lib/grape/error_formatter/xml.rb +4 -6
  20. data/lib/grape/exceptions/base.rb +9 -9
  21. data/lib/grape/exceptions/incompatible_option_values.rb +10 -0
  22. data/lib/grape/exceptions/invalid_formatter.rb +1 -4
  23. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -5
  24. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -6
  25. data/lib/grape/exceptions/missing_mime_type.rb +1 -5
  26. data/lib/grape/exceptions/missing_option.rb +1 -4
  27. data/lib/grape/exceptions/missing_vendor_option.rb +1 -4
  28. data/lib/grape/exceptions/unknown_options.rb +1 -5
  29. data/lib/grape/exceptions/unknown_validator.rb +1 -3
  30. data/lib/grape/exceptions/validation.rb +13 -3
  31. data/lib/grape/exceptions/validation_errors.rb +43 -0
  32. data/lib/grape/formatter/base.rb +5 -7
  33. data/lib/grape/formatter/json.rb +0 -3
  34. data/lib/grape/formatter/serializable_hash.rb +15 -15
  35. data/lib/grape/formatter/txt.rb +0 -2
  36. data/lib/grape/formatter/xml.rb +0 -2
  37. data/lib/grape/http/request.rb +26 -0
  38. data/lib/grape/locale/en.yml +8 -5
  39. data/lib/grape/middleware/auth/base.rb +30 -0
  40. data/lib/grape/middleware/auth/basic.rb +3 -20
  41. data/lib/grape/middleware/auth/digest.rb +2 -19
  42. data/lib/grape/middleware/auth/oauth2.rb +31 -24
  43. data/lib/grape/middleware/base.rb +7 -7
  44. data/lib/grape/middleware/error.rb +36 -22
  45. data/lib/grape/middleware/filter.rb +3 -3
  46. data/lib/grape/middleware/formatter.rb +99 -61
  47. data/lib/grape/middleware/globals.rb +13 -0
  48. data/lib/grape/middleware/versioner/accept_version_header.rb +67 -0
  49. data/lib/grape/middleware/versioner/header.rb +22 -16
  50. data/lib/grape/middleware/versioner/param.rb +9 -11
  51. data/lib/grape/middleware/versioner/path.rb +10 -13
  52. data/lib/grape/middleware/versioner.rb +3 -1
  53. data/lib/grape/namespace.rb +23 -0
  54. data/lib/grape/parser/base.rb +3 -5
  55. data/lib/grape/parser/json.rb +0 -2
  56. data/lib/grape/parser/xml.rb +0 -2
  57. data/lib/grape/path.rb +70 -0
  58. data/lib/grape/route.rb +10 -6
  59. data/lib/grape/util/content_types.rb +2 -1
  60. data/lib/grape/util/deep_merge.rb +5 -5
  61. data/lib/grape/util/hash_stack.rb +13 -2
  62. data/lib/grape/validations/coerce.rb +11 -10
  63. data/lib/grape/validations/default.rb +25 -0
  64. data/lib/grape/validations/presence.rb +7 -3
  65. data/lib/grape/validations/regexp.rb +2 -5
  66. data/lib/grape/validations/values.rb +17 -0
  67. data/lib/grape/validations.rb +161 -54
  68. data/lib/grape/version.rb +1 -1
  69. data/lib/grape.rb +19 -4
  70. data/spec/grape/api_spec.rb +897 -268
  71. data/spec/grape/endpoint_spec.rb +283 -66
  72. data/spec/grape/entity_spec.rb +132 -29
  73. data/spec/grape/exceptions/missing_mime_type_spec.rb +3 -9
  74. data/spec/grape/exceptions/validation_errors_spec.rb +19 -0
  75. data/spec/grape/middleware/auth/basic_spec.rb +8 -8
  76. data/spec/grape/middleware/auth/digest_spec.rb +5 -5
  77. data/spec/grape/middleware/auth/oauth2_spec.rb +81 -36
  78. data/spec/grape/middleware/base_spec.rb +8 -13
  79. data/spec/grape/middleware/error_spec.rb +13 -17
  80. data/spec/grape/middleware/exception_spec.rb +47 -27
  81. data/spec/grape/middleware/formatter_spec.rb +103 -41
  82. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +121 -0
  83. data/spec/grape/middleware/versioner/header_spec.rb +76 -51
  84. data/spec/grape/middleware/versioner/param_spec.rb +18 -18
  85. data/spec/grape/middleware/versioner/path_spec.rb +6 -6
  86. data/spec/grape/middleware/versioner_spec.rb +5 -2
  87. data/spec/grape/path_spec.rb +229 -0
  88. data/spec/grape/util/hash_stack_spec.rb +31 -32
  89. data/spec/grape/validations/coerce_spec.rb +116 -51
  90. data/spec/grape/validations/default_spec.rb +123 -0
  91. data/spec/grape/validations/presence_spec.rb +42 -44
  92. data/spec/grape/validations/regexp_spec.rb +9 -9
  93. data/spec/grape/validations/values_spec.rb +138 -0
  94. data/spec/grape/validations/zh-CN.yml +4 -3
  95. data/spec/grape/validations_spec.rb +681 -48
  96. data/spec/shared/versioning_examples.rb +22 -6
  97. data/spec/spec_helper.rb +3 -2
  98. data/spec/support/basic_auth_encode_helpers.rb +0 -1
  99. data/spec/support/content_type_helpers.rb +11 -0
  100. data/spec/support/versioned_helpers.rb +13 -5
  101. metadata +34 -84
@@ -1,12 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::Util::HashStack do
4
- let(:klass){ Grape::Util::HashStack }
5
4
 
6
5
  describe '#get' do
7
6
  it 'finds the first available key' do
8
7
  subject[:abc] = 123
9
- subject.push(:abc => 345)
8
+ subject.push(abc: 345)
10
9
  subject.get(:abc).should == 345
11
10
  end
12
11
 
@@ -26,105 +25,105 @@ describe Grape::Util::HashStack do
26
25
  describe '#imbue' do
27
26
  it 'pushes a new value onto the end of an array' do
28
27
  subject[:abc] = []
29
- subject.imbue(:abc, [123])
30
- subject.imbue(:abc, [456])
28
+ subject.imbue :abc, [123]
29
+ subject.imbue :abc, [456]
31
30
  subject[:abc].should == [123, 456]
32
31
  end
33
32
 
34
33
  it 'merges a hash that is passed' do
35
- subject[:abc] = {:foo => 'bar'}
36
- subject.imbue(:abc, {:baz => 'wich'})
37
- subject[:abc].should == {:foo => 'bar', :baz => 'wich'}
34
+ subject[:abc] = { foo: 'bar' }
35
+ subject.imbue :abc, baz: 'wich'
36
+ subject[:abc].should == { foo: 'bar', baz: 'wich' }
38
37
  end
39
38
 
40
39
  it 'sets the value if not a hash or array' do
41
- subject.imbue(:abc, 123)
40
+ subject.imbue :abc, 123
42
41
  subject[:abc].should == 123
43
42
  end
44
43
 
45
44
  it 'is able to imbue an array without explicit setting' do
46
- subject.imbue(:arr, [1])
47
- subject.imbue(:arr, [2])
48
- subject[:arr].should == [1,2]
45
+ subject.imbue :arr, [1]
46
+ subject.imbue :arr, [2]
47
+ subject[:arr].should == [1, 2]
49
48
  end
50
49
 
51
50
  it 'is able to imbue a hash without explicit setting' do
52
- subject.imbue(:hash, :foo => 'bar')
53
- subject.imbue(:hash, :baz => 'wich')
54
- subject[:hash].should == {:foo => 'bar', :baz => 'wich'}
51
+ subject.imbue :hash, foo: 'bar'
52
+ subject.imbue :hash, baz: 'wich'
53
+ subject[:hash].should == { foo: 'bar', baz: 'wich' }
55
54
  end
56
55
  end
57
56
 
58
57
  describe '#push' do
59
58
  it 'returns a HashStack' do
60
- subject.push(klass.new).should be_kind_of(klass)
59
+ subject.push(Grape::Util::HashStack.new).should be_kind_of(Grape::Util::HashStack)
61
60
  end
62
61
 
63
62
  it 'places the passed value on the top of the stack' do
64
- subject.push(:abc => 123)
65
- subject.stack.should == [{}, {:abc => 123}]
63
+ subject.push(abc: 123)
64
+ subject.stack.should == [{}, { abc: 123 }]
66
65
  end
67
66
 
68
67
  it 'pushes an empty hash by default' do
69
68
  subject[:abc] = 123
70
69
  subject.push
71
- subject.stack.should == [{:abc => 123}, {}]
70
+ subject.stack.should == [{ abc: 123 }, {}]
72
71
  end
73
72
  end
74
73
 
75
74
  describe '#pop' do
76
75
  it 'removes and return the top frame' do
77
- subject.push(:abc => 123)
78
- subject.pop.should == {:abc => 123}
76
+ subject.push(abc: 123)
77
+ subject.pop.should == { abc: 123 }
79
78
  subject.stack.size.should == 1
80
79
  end
81
80
  end
82
81
 
83
82
  describe '#peek' do
84
83
  it 'returns the top frame without removing it' do
85
- subject.push(:abc => 123)
86
- subject.peek.should == {:abc => 123}
84
+ subject.push(abc: 123)
85
+ subject.peek.should == { abc: 123 }
87
86
  subject.stack.size.should == 2
88
87
  end
89
88
  end
90
89
 
91
90
  describe '#prepend' do
92
91
  it 'returns a HashStack' do
93
- subject.prepend(klass.new).should be_kind_of(klass)
92
+ subject.prepend(Grape::Util::HashStack.new).should be_kind_of(Grape::Util::HashStack)
94
93
  end
95
94
 
96
95
  it "prepends a HashStack's stack onto its own stack" do
97
- other = klass.new.push(:abc => 123)
98
- subject.prepend(other).stack.should == [{}, {:abc => 123}, {}]
96
+ other = Grape::Util::HashStack.new.push(abc: 123)
97
+ subject.prepend(other).stack.should == [{}, { abc: 123 }, {}]
99
98
  end
100
99
  end
101
100
 
102
101
  describe '#concat' do
103
102
  it 'returns a HashStack' do
104
- subject.concat(klass.new).should be_kind_of(klass)
103
+ subject.concat(Grape::Util::HashStack.new).should be_kind_of(Grape::Util::HashStack)
105
104
  end
106
105
 
107
106
  it "appends a HashStack's stack onto its own stack" do
108
- other = klass.new.push(:abc => 123)
109
- subject.concat(other).stack.should == [{}, {}, {:abc => 123}]
107
+ other = Grape::Util::HashStack.new.push(abc: 123)
108
+ subject.concat(other).stack.should == [{}, {}, { abc: 123 }]
110
109
  end
111
110
  end
112
111
 
113
112
  describe '#update' do
114
113
  it 'merges! into the top frame' do
115
- subject.update(:abc => 123)
116
- subject.stack.should == [{:abc => 123}]
114
+ subject.update(abc: 123)
115
+ subject.stack.should == [{ abc: 123 }]
117
116
  end
118
117
 
119
118
  it 'returns a HashStack' do
120
- subject.update(:abc => 123).should be_kind_of(klass)
119
+ subject.update(abc: 123).should be_kind_of(Grape::Util::HashStack)
121
120
  end
122
121
  end
123
122
 
124
123
  describe '#clone' do
125
124
  it 'performs a deep copy' do
126
125
  subject[:abc] = 123
127
- subject.push :def => 234
126
+ subject.push def: 234
128
127
  clone = subject.clone
129
128
  clone[:def] = 345
130
129
  subject[:def].should == 234
@@ -2,45 +2,84 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Grape::Validations::CoerceValidator do
5
- subject { Class.new(Grape::API) }
6
- def app; subject end
5
+ subject do
6
+ Class.new(Grape::API)
7
+ end
8
+
9
+ def app
10
+ subject
11
+ end
7
12
 
8
13
  describe 'coerce' do
9
- it "i18n error on malformed input" do
10
- I18n.load_path << File.expand_path('../zh-CN.yml',__FILE__)
11
- I18n.reload!
12
- I18n.locale = :'zh-CN'
13
- subject.params { requires :age, :type => Integer }
14
- subject.get '/single' do 'int works'; end
15
-
16
- get '/single', :age => '43a'
17
- last_response.status.should == 400
18
- last_response.body.should == '年龄格式不正确'
19
- I18n.locale = :en
14
+
15
+ context "i18n" do
16
+
17
+ after :each do
18
+ I18n.locale = :en
19
+ end
20
+
21
+ it "i18n error on malformed input" do
22
+ I18n.load_path << File.expand_path('../zh-CN.yml', __FILE__)
23
+ I18n.reload!
24
+ I18n.locale = 'zh-CN'.to_sym
25
+ subject.params do
26
+ requires :age, type: Integer
27
+ end
28
+ subject.get '/single' do
29
+ 'int works'
30
+ end
31
+
32
+ get '/single', age: '43a'
33
+ last_response.status.should == 400
34
+ last_response.body.should == '年龄格式不正确'
35
+ end
36
+
37
+ it 'gives an english fallback error when default locale message is blank' do
38
+ I18n.locale = 'pt-BR'.to_sym
39
+ subject.params do
40
+ requires :age, type: Integer
41
+ end
42
+ subject.get '/single' do
43
+ 'int works'
44
+ end
45
+
46
+ get '/single', age: '43a'
47
+ last_response.status.should == 400
48
+ last_response.body.should == 'age is invalid'
49
+ end
20
50
 
21
51
  end
52
+
22
53
  it 'error on malformed input' do
23
- subject.params { requires :int, :type => Integer }
24
- subject.get '/single' do 'int works'; end
54
+ subject.params do
55
+ requires :int, type: Integer
56
+ end
57
+ subject.get '/single' do
58
+ 'int works'
59
+ end
25
60
 
26
- get '/single', :int => '43a'
61
+ get '/single', int: '43a'
27
62
  last_response.status.should == 400
28
- last_response.body.should == 'invalid parameter: int'
63
+ last_response.body.should == 'int is invalid'
29
64
 
30
- get '/single', :int => '43'
65
+ get '/single', int: '43'
31
66
  last_response.status.should == 200
32
67
  last_response.body.should == 'int works'
33
68
  end
34
69
 
35
70
  it 'error on malformed input (Array)' do
36
- subject.params { requires :ids, :type => Array[Integer] }
37
- subject.get '/array' do 'array int works'; end
71
+ subject.params do
72
+ requires :ids, type: Array[Integer]
73
+ end
74
+ subject.get '/array' do
75
+ 'array int works'
76
+ end
38
77
 
39
- get 'array', { :ids => ['1', '2', 'az'] }
78
+ get 'array', ids: ['1', '2', 'az']
40
79
  last_response.status.should == 400
41
- last_response.body.should == 'invalid parameter: ids'
80
+ last_response.body.should == 'ids is invalid'
42
81
 
43
- get 'array', { :ids => ['1', '2', '890'] }
82
+ get 'array', ids: ['1', '2', '890']
44
83
  last_response.status.should == 200
45
84
  last_response.body.should == 'array int works'
46
85
  end
@@ -48,21 +87,25 @@ describe Grape::Validations::CoerceValidator do
48
87
  context 'complex objects' do
49
88
  module CoerceValidatorSpec
50
89
  class User
51
- include Virtus
90
+ include Virtus.model
52
91
  attribute :id, Integer
53
92
  attribute :name, String
54
93
  end
55
94
  end
56
95
 
57
96
  it 'error on malformed input for complex objects' do
58
- subject.params { requires :user, :type => CoerceValidatorSpec::User }
59
- subject.get '/user' do 'complex works'; end
97
+ subject.params do
98
+ requires :user, type: CoerceValidatorSpec::User
99
+ end
100
+ subject.get '/user' do
101
+ 'complex works'
102
+ end
60
103
 
61
- get '/user', :user => "32"
104
+ get '/user', user: "32"
62
105
  last_response.status.should == 400
63
- last_response.body.should == 'invalid parameter: user'
106
+ last_response.body.should == 'user is invalid'
64
107
 
65
- get '/user', :user => { :id => 32, :name => 'Bob' }
108
+ get '/user', user: { id: 32, name: 'Bob' }
66
109
  last_response.status.should == 200
67
110
  last_response.body.should == 'complex works'
68
111
  end
@@ -70,71 +113,93 @@ describe Grape::Validations::CoerceValidator do
70
113
 
71
114
  context 'coerces' do
72
115
  it 'Integer' do
73
- subject.params { requires :int, :coerce => Integer }
74
- subject.get '/int' do params[:int].class; end
116
+ subject.params do
117
+ requires :int, coerce: Integer
118
+ end
119
+ subject.get '/int' do
120
+ params[:int].class
121
+ end
75
122
 
76
- get '/int', { :int => "45" }
123
+ get '/int', int: "45"
77
124
  last_response.status.should == 200
78
125
  last_response.body.should == 'Fixnum'
79
126
  end
80
127
 
81
128
  it 'Array of Integers' do
82
- subject.params { requires :arry, :coerce => Array[Integer] }
83
- subject.get '/array' do params[:arry][0].class; end
129
+ subject.params do
130
+ requires :arry, coerce: Array[Integer]
131
+ end
132
+ subject.get '/array' do
133
+ params[:arry][0].class
134
+ end
84
135
 
85
- get '/array', { :arry => [ '1', '2', '3' ] }
136
+ get '/array', arry: ['1', '2', '3']
86
137
  last_response.status.should == 200
87
138
  last_response.body.should == 'Fixnum'
88
139
  end
89
140
 
90
141
  it 'Array of Bools' do
91
- subject.params { requires :arry, :coerce => Array[Virtus::Attribute::Boolean] }
92
- subject.get '/array' do params[:arry][0].class; end
142
+ subject.params do
143
+ requires :arry, coerce: Array[Virtus::Attribute::Boolean]
144
+ end
145
+ subject.get '/array' do
146
+ params[:arry][0].class
147
+ end
93
148
 
94
- get 'array', { :arry => [1, 0] }
149
+ get 'array', arry: [1, 0]
95
150
  last_response.status.should == 200
96
151
  last_response.body.should == 'TrueClass'
97
152
  end
98
153
 
99
154
  it 'Bool' do
100
- subject.params { requires :bool, :coerce => Virtus::Attribute::Boolean }
101
- subject.get '/bool' do params[:bool].class; end
155
+ subject.params do
156
+ requires :bool, coerce: Virtus::Attribute::Boolean
157
+ end
158
+ subject.get '/bool' do
159
+ params[:bool].class
160
+ end
102
161
 
103
- get '/bool', { :bool => 1 }
162
+ get '/bool', bool: 1
104
163
  last_response.status.should == 200
105
164
  last_response.body.should == 'TrueClass'
106
165
 
107
- get '/bool', { :bool => 0 }
166
+ get '/bool', bool: 0
108
167
  last_response.status.should == 200
109
168
  last_response.body.should == 'FalseClass'
110
169
 
111
- get '/bool', { :bool => 'false' }
170
+ get '/bool', bool: 'false'
112
171
  last_response.status.should == 200
113
172
  last_response.body.should == 'FalseClass'
114
173
 
115
- get '/bool', { :bool => 'true' }
174
+ get '/bool', bool: 'true'
116
175
  last_response.status.should == 200
117
176
  last_response.body.should == 'TrueClass'
118
177
  end
119
178
 
120
179
  it 'file' do
121
- subject.params { requires :file, :coerce => Rack::Multipart::UploadedFile }
122
- subject.post '/upload' do params[:file].filename; end
180
+ subject.params do
181
+ requires :file, coerce: Rack::Multipart::UploadedFile
182
+ end
183
+ subject.post '/upload' do
184
+ params[:file].filename
185
+ end
123
186
 
124
- post '/upload', { :file => Rack::Test::UploadedFile.new(__FILE__) }
187
+ post '/upload', file: Rack::Test::UploadedFile.new(__FILE__)
125
188
  last_response.status.should == 201
126
189
  last_response.body.should == File.basename(__FILE__).to_s
127
190
  end
128
191
 
129
192
  it 'Nests integers' do
130
193
  subject.params do
131
- group :integers do
132
- requires :int, :coerce => Integer
194
+ requires :integers, type: Hash do
195
+ requires :int, coerce: Integer
133
196
  end
134
197
  end
135
- subject.get '/int' do params[:integers][:int].class; end
198
+ subject.get '/int' do
199
+ params[:integers][:int].class
200
+ end
136
201
 
137
- get '/int', { :integers => { :int => "45" } }
202
+ get '/int', integers: { int: "45" }
138
203
  last_response.status.should == 200
139
204
  last_response.body.should == 'Fixnum'
140
205
  end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::Validations::DefaultValidator do
4
+
5
+ module ValidationsSpec
6
+ module DefaultValidatorSpec
7
+ class API < Grape::API
8
+ default_format :json
9
+
10
+ params do
11
+ optional :id
12
+ optional :type, default: 'default-type'
13
+ end
14
+ get '/' do
15
+ { id: params[:id], type: params[:type] }
16
+ end
17
+
18
+ params do
19
+ optional :type1, default: 'default-type1'
20
+ optional :type2, default: 'default-type2'
21
+ end
22
+ get '/user' do
23
+ { type1: params[:type1], type2: params[:type2] }
24
+ end
25
+
26
+ params do
27
+ requires :id
28
+ optional :type1, default: 'default-type1'
29
+ optional :type2, default: 'default-type2'
30
+ end
31
+
32
+ get '/message' do
33
+ { id: params[:id], type1: params[:type1], type2: params[:type2] }
34
+ end
35
+
36
+ params do
37
+ optional :random, default: -> { Random.rand }
38
+ optional :not_random, default: Random.rand
39
+ end
40
+ get '/numbers' do
41
+ { random_number: params[:random], non_random_number: params[:non_random_number] }
42
+ end
43
+
44
+ params do
45
+ # NOTE: The :foo parameter could be made required with json body
46
+ # params, and then an empty hash would be valid. With query parameters
47
+ # it must be optional if it isn't provided at all, as otherwise
48
+ # the validaton for the Hash itself fails because there is no such
49
+ # thing as an empty hash.
50
+ optional :foo, type: Hash do
51
+ optional :bar, default: 'foo-bar'
52
+ end
53
+ end
54
+ get '/group' do
55
+ { foo_bar: params[:foo][:bar] }
56
+ end
57
+
58
+ params do
59
+ optional :array, type: Array do
60
+ requires :name
61
+ optional :with_default, default: 'default'
62
+ end
63
+ end
64
+ get '/array' do
65
+ { array: params[:array] }
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def app
72
+ ValidationsSpec::DefaultValidatorSpec::API
73
+ end
74
+
75
+ it 'set default value for optional param' do
76
+ get("/")
77
+ last_response.status.should == 200
78
+ last_response.body.should == { id: nil, type: 'default-type' }.to_json
79
+ end
80
+
81
+ it 'set default values for optional params' do
82
+ get("/user")
83
+ last_response.status.should == 200
84
+ last_response.body.should == { type1: 'default-type1', type2: 'default-type2' }.to_json
85
+ end
86
+
87
+ it 'set default values for missing params in the request' do
88
+ get("/user?type2=value2")
89
+ last_response.status.should == 200
90
+ last_response.body.should == { type1: 'default-type1', type2: 'value2' }.to_json
91
+ end
92
+
93
+ it 'set default values for optional params and allow to use required fields in the same time' do
94
+ get("/message?id=1")
95
+ last_response.status.should == 200
96
+ last_response.body.should == { id: '1', type1: 'default-type1', type2: 'default-type2' }.to_json
97
+ end
98
+
99
+ it 'sets lambda based defaults at the time of call' do
100
+ get("/numbers")
101
+ last_response.status.should == 200
102
+ before = JSON.parse(last_response.body)
103
+ get("/numbers")
104
+ last_response.status.should == 200
105
+ after = JSON.parse(last_response.body)
106
+
107
+ before['non_random_number'].should == after['non_random_number']
108
+ before['random_number'].should_not == after['random_number']
109
+ end
110
+
111
+ it 'set default values for optional grouped params' do
112
+ get('/group')
113
+ last_response.status.should == 200
114
+ last_response.body.should == { foo_bar: 'foo-bar' }.to_json
115
+ end
116
+
117
+ it 'sets default values for grouped arrays' do
118
+ get('/array?array[][name]=name&array[][name]=name2&array[][with_default]=bar2')
119
+ last_response.status.should == 200
120
+ last_response.body.should == { array: [{ name: "name", with_default: "default" }, { name: "name2", with_default: "bar2" }] }.to_json
121
+ end
122
+
123
+ end