grape 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +23 -80
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG.md +27 -0
  5. data/Gemfile +1 -1
  6. data/Guardfile +1 -1
  7. data/LICENSE +1 -1
  8. data/README.md +131 -30
  9. data/Rakefile +1 -1
  10. data/UPGRADING.md +110 -1
  11. data/gemfiles/rails_3.gemfile +1 -1
  12. data/gemfiles/rails_4.gemfile +1 -1
  13. data/grape.gemspec +4 -4
  14. data/lib/grape.rb +92 -62
  15. data/lib/grape/api.rb +10 -10
  16. data/lib/grape/cookies.rb +1 -1
  17. data/lib/grape/dsl/configuration.rb +7 -7
  18. data/lib/grape/dsl/helpers.rb +3 -3
  19. data/lib/grape/dsl/inside_route.rb +50 -21
  20. data/lib/grape/dsl/parameters.rb +25 -6
  21. data/lib/grape/dsl/request_response.rb +1 -1
  22. data/lib/grape/dsl/routing.rb +11 -10
  23. data/lib/grape/dsl/settings.rb +1 -1
  24. data/lib/grape/endpoint.rb +21 -19
  25. data/lib/grape/error_formatter/json.rb +1 -1
  26. data/lib/grape/exceptions/base.rb +1 -1
  27. data/lib/grape/exceptions/validation.rb +1 -1
  28. data/lib/grape/exceptions/validation_errors.rb +2 -2
  29. data/lib/grape/formatter/base.rb +1 -1
  30. data/lib/grape/formatter/json.rb +1 -1
  31. data/lib/grape/formatter/serializable_hash.rb +4 -4
  32. data/lib/grape/formatter/txt.rb +1 -1
  33. data/lib/grape/formatter/xml.rb +1 -1
  34. data/lib/grape/http/headers.rb +27 -0
  35. data/lib/grape/http/request.rb +1 -1
  36. data/lib/grape/middleware/error.rb +10 -4
  37. data/lib/grape/middleware/formatter.rb +13 -9
  38. data/lib/grape/middleware/globals.rb +2 -1
  39. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -2
  40. data/lib/grape/middleware/versioner/header.rb +4 -4
  41. data/lib/grape/middleware/versioner/param.rb +2 -2
  42. data/lib/grape/middleware/versioner/path.rb +1 -1
  43. data/lib/grape/namespace.rb +2 -1
  44. data/lib/grape/parser/json.rb +1 -1
  45. data/lib/grape/parser/xml.rb +1 -1
  46. data/lib/grape/path.rb +3 -3
  47. data/lib/grape/presenters/presenter.rb +9 -0
  48. data/lib/grape/validations/params_scope.rb +3 -3
  49. data/lib/grape/validations/validators/allow_blank.rb +1 -1
  50. data/lib/grape/validations/validators/coerce.rb +6 -5
  51. data/lib/grape/validations/validators/default.rb +2 -2
  52. data/lib/grape/validations/validators/multiple_params_base.rb +1 -0
  53. data/lib/grape/validations/validators/regexp.rb +1 -1
  54. data/lib/grape/version.rb +1 -1
  55. data/spec/grape/api/custom_validations_spec.rb +47 -0
  56. data/spec/grape/api/deeply_included_options_spec.rb +56 -0
  57. data/spec/grape/api_spec.rb +64 -42
  58. data/spec/grape/dsl/configuration_spec.rb +2 -2
  59. data/spec/grape/dsl/helpers_spec.rb +1 -1
  60. data/spec/grape/dsl/inside_route_spec.rb +75 -19
  61. data/spec/grape/dsl/parameters_spec.rb +59 -10
  62. data/spec/grape/dsl/request_response_spec.rb +62 -2
  63. data/spec/grape/dsl/routing_spec.rb +116 -18
  64. data/spec/grape/endpoint_spec.rb +57 -5
  65. data/spec/grape/entity_spec.rb +1 -1
  66. data/spec/grape/exceptions/body_parse_errors_spec.rb +5 -5
  67. data/spec/grape/exceptions/invalid_accept_header_spec.rb +32 -32
  68. data/spec/grape/exceptions/validation_errors_spec.rb +1 -1
  69. data/spec/grape/integration/rack_spec.rb +4 -3
  70. data/spec/grape/middleware/auth/strategies_spec.rb +2 -2
  71. data/spec/grape/middleware/base_spec.rb +2 -2
  72. data/spec/grape/middleware/error_spec.rb +1 -1
  73. data/spec/grape/middleware/exception_spec.rb +5 -5
  74. data/spec/grape/middleware/formatter_spec.rb +10 -10
  75. data/spec/grape/middleware/globals_spec.rb +27 -0
  76. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +1 -1
  77. data/spec/grape/middleware/versioner/header_spec.rb +1 -1
  78. data/spec/grape/middleware/versioner/param_spec.rb +1 -1
  79. data/spec/grape/middleware/versioner/path_spec.rb +1 -1
  80. data/spec/grape/path_spec.rb +6 -4
  81. data/spec/grape/presenters/presenter_spec.rb +70 -0
  82. data/spec/grape/util/inheritable_values_spec.rb +1 -1
  83. data/spec/grape/util/stackable_values_spec.rb +1 -1
  84. data/spec/grape/util/strict_hash_configuration_spec.rb +1 -1
  85. data/spec/grape/validations/params_scope_spec.rb +64 -0
  86. data/spec/grape/validations/validators/allow_blank_spec.rb +10 -0
  87. data/spec/grape/validations/validators/coerce_spec.rb +48 -18
  88. data/spec/grape/validations/validators/default_spec.rb +110 -20
  89. data/spec/grape/validations/validators/presence_spec.rb +41 -3
  90. data/spec/grape/validations/validators/regexp_spec.rb +7 -2
  91. data/spec/grape/validations_spec.rb +20 -1
  92. data/spec/support/file_streamer.rb +11 -0
  93. data/spec/support/versioned_helpers.rb +1 -1
  94. metadata +14 -2
@@ -40,20 +40,6 @@ describe Grape::Validations::DefaultValidator do
40
40
  { random_number: params[:random], non_random_number: params[:non_random_number] }
41
41
  end
42
42
 
43
- params do
44
- # NOTE: The :foo parameter could be made required with json body
45
- # params, and then an empty hash would be valid. With query parameters
46
- # it must be optional if it isn't provided at all, as otherwise
47
- # the validaton for the Hash itself fails because there is no such
48
- # thing as an empty hash.
49
- optional :foo, type: Hash do
50
- optional :bar, default: 'foo-bar'
51
- end
52
- end
53
- get '/group' do
54
- { foo_bar: params[:foo][:bar] }
55
- end
56
-
57
43
  params do
58
44
  optional :array, type: Array do
59
45
  requires :name
@@ -107,15 +93,119 @@ describe Grape::Validations::DefaultValidator do
107
93
  expect(before['random_number']).not_to eq(after['random_number'])
108
94
  end
109
95
 
110
- it 'set default values for optional grouped params' do
111
- get('/group')
112
- expect(last_response.status).to eq(200)
113
- expect(last_response.body).to eq({ foo_bar: 'foo-bar' }.to_json)
114
- end
115
-
116
96
  it 'sets default values for grouped arrays' do
117
97
  get('/array?array[][name]=name&array[][name]=name2&array[][with_default]=bar2')
118
98
  expect(last_response.status).to eq(200)
119
99
  expect(last_response.body).to eq({ array: [{ name: 'name', with_default: 'default' }, { name: 'name2', with_default: 'bar2' }] }.to_json)
120
100
  end
101
+
102
+ context 'optional group with defaults' do
103
+ subject do
104
+ Class.new(Grape::API) do
105
+ default_format :json
106
+ end
107
+ end
108
+
109
+ def app
110
+ subject
111
+ end
112
+
113
+ context 'optional array without default value includes optional param with default value' do
114
+ before do
115
+ subject.params do
116
+ optional :optional_array, type: Array do
117
+ optional :foo_in_optional_array, default: 'bar'
118
+ end
119
+ end
120
+ subject.post '/optional_array' do
121
+ { optional_array: params[:optional_array] }
122
+ end
123
+ end
124
+
125
+ it 'returns nil for optional array if param is not provided' do
126
+ post '/optional_array'
127
+ expect(last_response.status).to eq(201)
128
+ expect(last_response.body).to eq({ optional_array: nil }.to_json)
129
+ end
130
+ end
131
+
132
+ context 'optional array with default value includes optional param with default value' do
133
+ before do
134
+ subject.params do
135
+ optional :optional_array_with_default, type: Array, default: [] do
136
+ optional :foo_in_optional_array, default: 'bar'
137
+ end
138
+ end
139
+ subject.post '/optional_array_with_default' do
140
+ { optional_array_with_default: params[:optional_array_with_default] }
141
+ end
142
+ end
143
+
144
+ it 'sets default value for optional array if param is not provided' do
145
+ post '/optional_array_with_default'
146
+ expect(last_response.status).to eq(201)
147
+ expect(last_response.body).to eq({ optional_array_with_default: [] }.to_json)
148
+ end
149
+ end
150
+
151
+ context 'optional hash without default value includes optional param with default value' do
152
+ before do
153
+ subject.params do
154
+ optional :optional_hash_without_default, type: Hash do
155
+ optional :foo_in_optional_hash, default: 'bar'
156
+ end
157
+ end
158
+ subject.post '/optional_hash_without_default' do
159
+ { optional_hash_without_default: params[:optional_hash_without_default] }
160
+ end
161
+ end
162
+
163
+ it 'returns nil for optional hash if param is not provided' do
164
+ post '/optional_hash_without_default'
165
+ expect(last_response.status).to eq(201)
166
+ expect(last_response.body).to eq({ optional_hash_without_default: nil }.to_json)
167
+ end
168
+ end
169
+
170
+ context 'optional hash with default value includes optional param with default value' do
171
+ before do
172
+ subject.params do
173
+ optional :optional_hash_with_default, type: Hash, default: {} do
174
+ optional :foo_in_optional_hash, default: 'bar'
175
+ end
176
+ end
177
+ subject.post '/optional_hash_with_default_empty_hash' do
178
+ { optional_hash_with_default: params[:optional_hash_with_default] }
179
+ end
180
+
181
+ subject.params do
182
+ optional :optional_hash_with_default, type: Hash, default: { foo_in_optional_hash: 'parent_default' } do
183
+ optional :some_param
184
+ optional :foo_in_optional_hash, default: 'own_default'
185
+ end
186
+ end
187
+ subject.post '/optional_hash_with_default_inner_params' do
188
+ { foo_in_optional_hash: params[:optional_hash_with_default][:foo_in_optional_hash] }
189
+ end
190
+ end
191
+
192
+ it 'sets default value for optional hash if param is not provided' do
193
+ post '/optional_hash_with_default_empty_hash'
194
+ expect(last_response.status).to eq(201)
195
+ expect(last_response.body).to eq({ optional_hash_with_default: {} }.to_json)
196
+ end
197
+
198
+ it 'sets default value from parent defaults for inner param if parent param is not provided' do
199
+ post '/optional_hash_with_default_inner_params'
200
+ expect(last_response.status).to eq(201)
201
+ expect(last_response.body).to eq({ foo_in_optional_hash: 'parent_default' }.to_json)
202
+ end
203
+
204
+ it 'sets own default value for inner param if parent param is provided' do
205
+ post '/optional_hash_with_default_inner_params', optional_hash_with_default: { some_param: 'param' }
206
+ expect(last_response.status).to eq(201)
207
+ expect(last_response.body).to eq({ foo_in_optional_hash: 'own_default' }.to_json)
208
+ end
209
+ end
210
+ end
121
211
  end
@@ -55,7 +55,7 @@ describe Grape::Validations::PresenceValidator do
55
55
  context 'with a required non-empty string' do
56
56
  before do
57
57
  subject.params do
58
- requires :email, type: String, regexp: /^\S+$/
58
+ requires :email, type: String, allow_blank: false, regexp: /^\S+$/
59
59
  end
60
60
  subject.get do
61
61
  'Hello'
@@ -64,12 +64,12 @@ describe Grape::Validations::PresenceValidator do
64
64
  it 'requires when missing' do
65
65
  get '/'
66
66
  expect(last_response.status).to eq(400)
67
- expect(last_response.body).to eq('{"error":"email is missing, email is invalid"}')
67
+ expect(last_response.body).to eq('{"error":"email is missing, email is empty"}')
68
68
  end
69
69
  it 'requires when empty' do
70
70
  get '/', email: ''
71
71
  expect(last_response.status).to eq(400)
72
- expect(last_response.body).to eq('{"error":"email is invalid"}')
72
+ expect(last_response.body).to eq('{"error":"email is empty, email is invalid"}')
73
73
  end
74
74
  it 'valid when set' do
75
75
  get '/', email: 'bob@example.com'
@@ -176,4 +176,42 @@ describe Grape::Validations::PresenceValidator do
176
176
  expect(last_response.body).to eq('Nested triple'.to_json)
177
177
  end
178
178
  end
179
+
180
+ context 'with reused parameter documentation once required and once optional' do
181
+ before do
182
+ docs = { name: { type: String, desc: 'some name' } }
183
+
184
+ subject.params do
185
+ requires :all, using: docs
186
+ end
187
+ subject.get '/required' do
188
+ 'Hello required'
189
+ end
190
+
191
+ subject.params do
192
+ optional :all, using: docs
193
+ end
194
+ subject.get '/optional' do
195
+ 'Hello optional'
196
+ end
197
+ end
198
+ it 'works with required' do
199
+ get '/required'
200
+ expect(last_response.status).to eq(400)
201
+ expect(last_response.body).to eq('{"error":"name is missing"}')
202
+
203
+ get '/required', name: 'Bob'
204
+ expect(last_response.status).to eq(200)
205
+ expect(last_response.body).to eq('Hello required'.to_json)
206
+ end
207
+ it 'works with optional' do
208
+ get '/optional'
209
+ expect(last_response.status).to eq(200)
210
+ expect(last_response.body).to eq('Hello optional'.to_json)
211
+
212
+ get '/optional', name: 'Bob'
213
+ expect(last_response.status).to eq(200)
214
+ expect(last_response.body).to eq('Hello optional'.to_json)
215
+ end
216
+ end
179
217
  end
@@ -25,12 +25,17 @@ describe Grape::Validations::RegexpValidator do
25
25
  expect(last_response.status).to eq(400)
26
26
  end
27
27
 
28
- it 'refuses nil' do
29
- get '/', name: nil
28
+ it 'refuses empty' do
29
+ get '/', name: ''
30
30
  expect(last_response.status).to eq(400)
31
31
  end
32
32
  end
33
33
 
34
+ it 'accepts nil' do
35
+ get '/', name: nil
36
+ expect(last_response.status).to eq(200)
37
+ end
38
+
34
39
  it 'accepts valid input' do
35
40
  get '/', name: 'bob'
36
41
  expect(last_response.status).to eq(200)
@@ -353,7 +353,7 @@ describe Grape::Validations do
353
353
  end
354
354
 
355
355
  context 'group params with nested params which has a type' do
356
- let(:invalid_items){ { items: '' } }
356
+ let(:invalid_items) { { items: '' } }
357
357
 
358
358
  before do
359
359
  subject.params do
@@ -1132,6 +1132,25 @@ describe Grape::Validations do
1132
1132
  expect(last_response.status).to eq(400)
1133
1133
  end
1134
1134
  end
1135
+
1136
+ context 'mutually exclusive params inside Hash group' do
1137
+ it 'invalidates if request param is invalid type' do
1138
+ subject.params do
1139
+ optional :wine, type: Hash do
1140
+ optional :grape
1141
+ optional :country
1142
+ mutually_exclusive :grape, :country
1143
+ end
1144
+ end
1145
+ subject.post '/mutually_exclusive' do
1146
+ 'mutually_exclusive works!'
1147
+ end
1148
+
1149
+ post '/mutually_exclusive', wine: '2015 sauvignon'
1150
+ expect(last_response.status).to eq(400)
1151
+ expect(last_response.body).to eq 'wine is invalid'
1152
+ end
1153
+ end
1135
1154
  end
1136
1155
 
1137
1156
  context 'exactly one of' do
@@ -0,0 +1,11 @@
1
+ class FileStreamer
2
+ def initialize(file_path)
3
+ @file_path = file_path
4
+ end
5
+
6
+ def each(&blk)
7
+ File.open(@file_path, 'rb') do |file|
8
+ file.each(10, &blk)
9
+ end
10
+ end
11
+ end
@@ -28,7 +28,7 @@ def versioned_headers(options)
28
28
  'HTTP_ACCEPT' => [
29
29
  "application/vnd.#{options[:vendor] }-#{options[:version] }",
30
30
  options[:format]
31
- ].compact.join('+')
31
+ ].compact.join('+')
32
32
  }
33
33
  when :accept_version_header
34
34
  {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-23 00:00:00.000000000 Z
11
+ date: 2015-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -360,6 +360,7 @@ files:
360
360
  - lib/grape/formatter/serializable_hash.rb
361
361
  - lib/grape/formatter/txt.rb
362
362
  - lib/grape/formatter/xml.rb
363
+ - lib/grape/http/headers.rb
363
364
  - lib/grape/http/request.rb
364
365
  - lib/grape/locale/en.yml
365
366
  - lib/grape/middleware/auth/base.rb
@@ -381,6 +382,7 @@ files:
381
382
  - lib/grape/parser/json.rb
382
383
  - lib/grape/parser/xml.rb
383
384
  - lib/grape/path.rb
385
+ - lib/grape/presenters/presenter.rb
384
386
  - lib/grape/route.rb
385
387
  - lib/grape/util/content_types.rb
386
388
  - lib/grape/util/inheritable_setting.rb
@@ -403,6 +405,8 @@ files:
403
405
  - lib/grape/validations/validators/regexp.rb
404
406
  - lib/grape/validations/validators/values.rb
405
407
  - lib/grape/version.rb
408
+ - spec/grape/api/custom_validations_spec.rb
409
+ - spec/grape/api/deeply_included_options_spec.rb
406
410
  - spec/grape/api/nested_helpers_spec.rb
407
411
  - spec/grape/api/shared_helpers_spec.rb
408
412
  - spec/grape/api_spec.rb
@@ -436,12 +440,14 @@ files:
436
440
  - spec/grape/middleware/error_spec.rb
437
441
  - spec/grape/middleware/exception_spec.rb
438
442
  - spec/grape/middleware/formatter_spec.rb
443
+ - spec/grape/middleware/globals_spec.rb
439
444
  - spec/grape/middleware/versioner/accept_version_header_spec.rb
440
445
  - spec/grape/middleware/versioner/header_spec.rb
441
446
  - spec/grape/middleware/versioner/param_spec.rb
442
447
  - spec/grape/middleware/versioner/path_spec.rb
443
448
  - spec/grape/middleware/versioner_spec.rb
444
449
  - spec/grape/path_spec.rb
450
+ - spec/grape/presenters/presenter_spec.rb
445
451
  - spec/grape/util/inheritable_setting_spec.rb
446
452
  - spec/grape/util/inheritable_values_spec.rb
447
453
  - spec/grape/util/stackable_values_spec.rb
@@ -465,6 +471,7 @@ files:
465
471
  - spec/support/basic_auth_encode_helpers.rb
466
472
  - spec/support/content_type_helpers.rb
467
473
  - spec/support/endpoint_faker.rb
474
+ - spec/support/file_streamer.rb
468
475
  - spec/support/versioned_helpers.rb
469
476
  homepage: https://github.com/intridea/grape
470
477
  licenses:
@@ -491,6 +498,8 @@ signing_key:
491
498
  specification_version: 4
492
499
  summary: A simple Ruby framework for building REST-like APIs.
493
500
  test_files:
501
+ - spec/grape/api/custom_validations_spec.rb
502
+ - spec/grape/api/deeply_included_options_spec.rb
494
503
  - spec/grape/api/nested_helpers_spec.rb
495
504
  - spec/grape/api/shared_helpers_spec.rb
496
505
  - spec/grape/api_spec.rb
@@ -524,12 +533,14 @@ test_files:
524
533
  - spec/grape/middleware/error_spec.rb
525
534
  - spec/grape/middleware/exception_spec.rb
526
535
  - spec/grape/middleware/formatter_spec.rb
536
+ - spec/grape/middleware/globals_spec.rb
527
537
  - spec/grape/middleware/versioner/accept_version_header_spec.rb
528
538
  - spec/grape/middleware/versioner/header_spec.rb
529
539
  - spec/grape/middleware/versioner/param_spec.rb
530
540
  - spec/grape/middleware/versioner/path_spec.rb
531
541
  - spec/grape/middleware/versioner_spec.rb
532
542
  - spec/grape/path_spec.rb
543
+ - spec/grape/presenters/presenter_spec.rb
533
544
  - spec/grape/util/inheritable_setting_spec.rb
534
545
  - spec/grape/util/inheritable_values_spec.rb
535
546
  - spec/grape/util/stackable_values_spec.rb
@@ -553,5 +564,6 @@ test_files:
553
564
  - spec/support/basic_auth_encode_helpers.rb
554
565
  - spec/support/content_type_helpers.rb
555
566
  - spec/support/endpoint_faker.rb
567
+ - spec/support/file_streamer.rb
556
568
  - spec/support/versioned_helpers.rb
557
569
  has_rdoc: