grape 0.12.0 → 0.13.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +2 -2
  3. data/CHANGELOG.md +237 -215
  4. data/CONTRIBUTING.md +4 -4
  5. data/README.md +133 -10
  6. data/RELEASING.md +14 -6
  7. data/Rakefile +1 -1
  8. data/UPGRADING.md +23 -23
  9. data/grape.gemspec +1 -3
  10. data/lib/grape/api.rb +24 -4
  11. data/lib/grape/dsl/callbacks.rb +20 -0
  12. data/lib/grape/dsl/configuration.rb +54 -0
  13. data/lib/grape/dsl/inside_route.rb +33 -1
  14. data/lib/grape/dsl/parameters.rb +80 -0
  15. data/lib/grape/dsl/routing.rb +14 -0
  16. data/lib/grape/dsl/settings.rb +36 -1
  17. data/lib/grape/dsl/validations.rb +7 -5
  18. data/lib/grape/endpoint.rb +42 -32
  19. data/lib/grape/exceptions/unknown_parameter.rb +10 -0
  20. data/lib/grape/exceptions/validation_errors.rb +4 -3
  21. data/lib/grape/http/headers.rb +0 -1
  22. data/lib/grape/http/request.rb +12 -4
  23. data/lib/grape/locale/en.yml +1 -0
  24. data/lib/grape/middleware/base.rb +1 -0
  25. data/lib/grape/middleware/formatter.rb +39 -23
  26. data/lib/grape/namespace.rb +13 -2
  27. data/lib/grape/path.rb +1 -0
  28. data/lib/grape/route.rb +5 -0
  29. data/lib/grape/util/file_response.rb +21 -0
  30. data/lib/grape/util/inheritable_setting.rb +23 -2
  31. data/lib/grape/util/inheritable_values.rb +1 -1
  32. data/lib/grape/util/parameter_types.rb +58 -0
  33. data/lib/grape/util/stackable_values.rb +5 -2
  34. data/lib/grape/validations/params_scope.rb +83 -9
  35. data/lib/grape/validations/validators/coerce.rb +11 -2
  36. data/lib/grape/validations.rb +5 -0
  37. data/lib/grape/version.rb +2 -1
  38. data/lib/grape.rb +7 -8
  39. data/spec/grape/api_spec.rb +63 -0
  40. data/spec/grape/dsl/inside_route_spec.rb +37 -2
  41. data/spec/grape/dsl/validations_spec.rb +18 -0
  42. data/spec/grape/endpoint_spec.rb +83 -0
  43. data/spec/grape/exceptions/validation_errors_spec.rb +28 -0
  44. data/spec/grape/middleware/base_spec.rb +33 -11
  45. data/spec/grape/middleware/formatter_spec.rb +0 -5
  46. data/spec/grape/util/inheritable_values_spec.rb +14 -0
  47. data/spec/grape/util/parameter_types_spec.rb +54 -0
  48. data/spec/grape/util/stackable_values_spec.rb +10 -0
  49. data/spec/grape/validations/params_scope_spec.rb +84 -0
  50. data/spec/grape/validations/validators/coerce_spec.rb +29 -8
  51. data/spec/grape/validations/validators/values_spec.rb +12 -0
  52. metadata +9 -6
  53. data/lib/backports/active_support/deep_dup.rb +0 -49
  54. data/lib/backports/active_support/duplicable.rb +0 -88
@@ -201,8 +201,43 @@ module Grape
201
201
  subject.file 'file'
202
202
  end
203
203
 
204
- it 'returns value' do
205
- expect(subject.file).to eq 'file'
204
+ it 'returns value wrapped in FileResponse' do
205
+ expect(subject.file).to eq Grape::Util::FileResponse.new('file')
206
+ end
207
+ end
208
+
209
+ it 'returns default' do
210
+ expect(subject.file).to be nil
211
+ end
212
+ end
213
+
214
+ describe '#stream' do
215
+ describe 'set' do
216
+ before do
217
+ subject.header 'Cache-Control', 'cache'
218
+ subject.header 'Content-Length', 123
219
+ subject.header 'Transfer-Encoding', 'base64'
220
+ subject.stream 'file'
221
+ end
222
+
223
+ it 'returns value wrapped in FileResponse' do
224
+ expect(subject.stream).to eq Grape::Util::FileResponse.new('file')
225
+ end
226
+
227
+ it 'also sets result of file to value wrapped in FileResponse' do
228
+ expect(subject.file).to eq Grape::Util::FileResponse.new('file')
229
+ end
230
+
231
+ it 'sets Cache-Control header to no-cache' do
232
+ expect(subject.header['Cache-Control']).to eq 'no-cache'
233
+ end
234
+
235
+ it 'sets Content-Length header to nil' do
236
+ expect(subject.header['Content-Length']).to eq nil
237
+ end
238
+
239
+ it 'sets Transfer-Encoding header to nil' do
240
+ expect(subject.header['Transfer-Encoding']).to eq nil
206
241
  end
207
242
  end
208
243
 
@@ -15,9 +15,15 @@ module Grape
15
15
  before do
16
16
  subject.namespace_stackable :declared_params, ['dummy']
17
17
  subject.namespace_stackable :validations, ['dummy']
18
+ subject.namespace_stackable :params, ['dummy']
19
+ subject.route_setting :description, description: 'lol', params: ['dummy']
18
20
  subject.reset_validations!
19
21
  end
20
22
 
23
+ after do
24
+ subject.unset_route_setting :description
25
+ end
26
+
21
27
  it 'resets declared params' do
22
28
  expect(subject.namespace_stackable(:declared_params)).to eq []
23
29
  end
@@ -25,6 +31,18 @@ module Grape
25
31
  it 'resets validations' do
26
32
  expect(subject.namespace_stackable(:validations)).to eq []
27
33
  end
34
+
35
+ it 'resets params' do
36
+ expect(subject.namespace_stackable(:params)).to eq []
37
+ end
38
+
39
+ it 'resets documentation params' do
40
+ expect(subject.route_setting(:description)[:params]).to be_nil
41
+ end
42
+
43
+ it 'does not reset documentation description' do
44
+ expect(subject.route_setting(:description)[:description]).to eq 'lol'
45
+ end
28
46
  end
29
47
 
30
48
  describe '.params' do
@@ -941,4 +941,87 @@ describe Grape::Endpoint do
941
941
  expect(last_response.body).to eq File.read(__FILE__)
942
942
  end
943
943
  end
944
+
945
+ context 'validation errors' do
946
+ before do
947
+ subject.before do
948
+ header['Access-Control-Allow-Origin'] = '*'
949
+ end
950
+ subject.params do
951
+ requires :id, type: String
952
+ end
953
+ subject.get do
954
+ 'should not get here'
955
+ end
956
+ end
957
+
958
+ it 'returns the errors, and passes headers' do
959
+ get '/'
960
+ expect(last_response.status).to eq 400
961
+ expect(last_response.body).to eq 'id is missing'
962
+ expect(last_response.headers['Access-Control-Allow-Origin']).to eq('*')
963
+ end
964
+ end
965
+
966
+ context 'instrumentation' do
967
+ before do
968
+ subject.before do
969
+ # Placeholder
970
+ end
971
+ subject.get do
972
+ 'hello'
973
+ end
974
+
975
+ @events = []
976
+ @subscriber = ActiveSupport::Notifications.subscribe(/grape/) do |*args|
977
+ @events << ActiveSupport::Notifications::Event.new(*args)
978
+ end
979
+ end
980
+
981
+ after do
982
+ ActiveSupport::Notifications.unsubscribe(@subscriber)
983
+ end
984
+
985
+ it 'notifies AS::N' do
986
+ get '/'
987
+
988
+ # In order that the events finalized (time each block ended)
989
+ expect(@events).to contain_exactly(
990
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
991
+ filters: a_collection_containing_exactly(an_instance_of(Proc)),
992
+ type: :before }),
993
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
994
+ filters: [],
995
+ type: :before_validation }),
996
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
997
+ filters: [],
998
+ type: :after_validation }),
999
+ have_attributes(name: 'endpoint_render.grape', payload: { endpoint: an_instance_of(Grape::Endpoint) }),
1000
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1001
+ filters: [],
1002
+ type: :after }),
1003
+ have_attributes(name: 'endpoint_run.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1004
+ env: an_instance_of(Hash) })
1005
+ )
1006
+
1007
+ # In order that events were initialized
1008
+ expect(@events.sort_by(&:time)).to contain_exactly(
1009
+ have_attributes(name: 'endpoint_run.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1010
+ env: an_instance_of(Hash) }),
1011
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1012
+ filters: a_collection_containing_exactly(an_instance_of(Proc)),
1013
+ type: :before }),
1014
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1015
+ filters: [],
1016
+ type: :before_validation }),
1017
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1018
+ filters: [],
1019
+ type: :after_validation }),
1020
+ have_attributes(name: 'endpoint_render.grape', payload: { endpoint: an_instance_of(Grape::Endpoint) }),
1021
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: an_instance_of(Grape::Endpoint),
1022
+ filters: [],
1023
+ type: :after })
1024
+ )
1025
+ end
1026
+ end
944
1027
  end
@@ -5,6 +5,22 @@ describe Grape::Exceptions::ValidationErrors do
5
5
  let(:validation_message) { 'FooBar is invalid' }
6
6
  let(:validation_error) { OpenStruct.new(params: [validation_message]) }
7
7
 
8
+ context 'initialize' do
9
+ let(:headers) {
10
+ {
11
+ 'A-Header-Key' => 'A-Header-Value'
12
+ }
13
+ }
14
+
15
+ subject do
16
+ described_class.new(errors: [validation_error], headers: headers)
17
+ end
18
+
19
+ it 'should assign headers through base class' do
20
+ expect(subject.headers).to eq(headers)
21
+ end
22
+ end
23
+
8
24
  context 'message' do
9
25
  context 'is not repeated' do
10
26
  let(:error) do
@@ -17,6 +33,18 @@ describe Grape::Exceptions::ValidationErrors do
17
33
  end
18
34
  end
19
35
 
36
+ describe '#full_messages' do
37
+ context 'with errors' do
38
+ let(:validation_error_1) { Grape::Exceptions::Validation.new(params: ['id'], message_key: 'presence') }
39
+ let(:validation_error_2) { Grape::Exceptions::Validation.new(params: ['name'], message_key: 'presence') }
40
+ subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
41
+
42
+ it 'returns an array with each errors full message' do
43
+ expect(subject).to contain_exactly('id is missing', 'name is missing')
44
+ end
45
+ end
46
+ end
47
+
20
48
  context 'api' do
21
49
  subject { Class.new(Grape::API) }
22
50
 
@@ -36,21 +36,43 @@ describe Grape::Middleware::Base do
36
36
 
37
37
  describe '#response' do
38
38
  subject { Grape::Middleware::Base.new(response) }
39
- let(:response) { ->(_) { [204, { abc: 1 }, 'test'] } }
40
39
 
41
- it 'status' do
42
- subject.call({})
43
- expect(subject.response.status).to eq(204)
44
- end
40
+ context Array do
41
+ let(:response) { ->(_) { [204, { abc: 1 }, 'test'] } }
42
+
43
+ it 'status' do
44
+ subject.call({})
45
+ expect(subject.response.status).to eq(204)
46
+ end
45
47
 
46
- it 'body' do
47
- subject.call({})
48
- expect(subject.response.body).to eq(['test'])
48
+ it 'body' do
49
+ subject.call({})
50
+ expect(subject.response.body).to eq(['test'])
51
+ end
52
+
53
+ it 'header' do
54
+ subject.call({})
55
+ expect(subject.response.header).to have_key(:abc)
56
+ end
49
57
  end
50
58
 
51
- it 'header' do
52
- subject.call({})
53
- expect(subject.response.header).to have_key(:abc)
59
+ context Rack::Response do
60
+ let(:response) { ->(_) { Rack::Response.new('test', 204, abc: 1) } }
61
+
62
+ it 'status' do
63
+ subject.call({})
64
+ expect(subject.response.status).to eq(204)
65
+ end
66
+
67
+ it 'body' do
68
+ subject.call({})
69
+ expect(subject.response.body).to eq(['test'])
70
+ end
71
+
72
+ it 'header' do
73
+ subject.call({})
74
+ expect(subject.response.header).to have_key(:abc)
75
+ end
54
76
  end
55
77
  end
56
78
 
@@ -110,11 +110,6 @@ describe Grape::Middleware::Formatter do
110
110
  expect(subject.env['api.format']).to eq(:xml)
111
111
  end
112
112
 
113
- it 'looks for case-indifferent headers' do
114
- subject.call('PATH_INFO' => '/info', 'http_accept' => 'application/xml')
115
- expect(subject.env['api.format']).to eq(:xml)
116
- end
117
-
118
113
  it 'uses quality rankings to determine formats' do
119
114
  subject.call('PATH_INFO' => '/info', 'HTTP_ACCEPT' => 'application/json; q=0.3,application/xml; q=1.0')
120
115
  expect(subject.env['api.format']).to eq(:xml)
@@ -58,6 +58,20 @@ module Grape
58
58
  expect(subject.to_hash).to eq(some_thing: :foo, some_thing_more: :foo_bar)
59
59
  end
60
60
  end
61
+
62
+ describe '#clone' do
63
+ let(:obj_cloned) { subject.clone }
64
+
65
+ context 'complex (i.e. not primitive) data types (ex. entity classes, please see bug #891)' do
66
+ let(:description) { { entity: double } }
67
+
68
+ before { subject[:description] = description }
69
+
70
+ it 'copies values; does not duplicate them' do
71
+ expect(obj_cloned[:description]).to eq description
72
+ end
73
+ end
74
+ end
61
75
  end
62
76
  end
63
77
  end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Grape::ParameterTypes do
4
+ class FooType
5
+ def self.parse(_)
6
+ end
7
+ end
8
+
9
+ class BarType
10
+ def self.parse
11
+ end
12
+ end
13
+
14
+ describe '::primitive?' do
15
+ [
16
+ Integer, Float, Numeric, BigDecimal,
17
+ Virtus::Attribute::Boolean, String, Symbol,
18
+ Date, DateTime, Time, Rack::Multipart::UploadedFile
19
+ ].each do |type|
20
+ it "recognizes #{type} as a primitive" do
21
+ expect(described_class.primitive?(type)).to be_truthy
22
+ end
23
+ end
24
+
25
+ it 'identifies unknown types' do
26
+ expect(described_class.primitive?(Object)).to be_falsy
27
+ expect(described_class.primitive?(FooType)).to be_falsy
28
+ end
29
+ end
30
+
31
+ describe '::structure?' do
32
+ [
33
+ Hash, Array, Set
34
+ ].each do |type|
35
+ it "recognizes #{type} as a structure" do
36
+ expect(described_class.structure?(type)).to be_truthy
37
+ end
38
+ end
39
+ end
40
+
41
+ describe '::custom_type?' do
42
+ it 'returns false if the type does not respond to :parse' do
43
+ expect(described_class.custom_type?(Object)).to be_falsy
44
+ end
45
+
46
+ it 'returns true if the type responds to :parse with one argument' do
47
+ expect(described_class.custom_type?(FooType)).to be_truthy
48
+ end
49
+
50
+ it 'returns false if the type\'s #parse method takes other than one argument' do
51
+ expect(described_class.custom_type?(BarType)).to be_falsy
52
+ end
53
+ end
54
+ end
@@ -109,6 +109,16 @@ module Grape
109
109
 
110
110
  expect(grandchild.clone.to_hash).to eq(some_thing: [:foo, [:bar, :more], :grand_foo_bar], some_thing_more: [:foo_bar])
111
111
  end
112
+
113
+ context 'complex (i.e. not primitive) data types (ex. middleware, please see bug #930)' do
114
+ let(:middleware) { double }
115
+
116
+ before { subject[:middleware] = middleware }
117
+
118
+ it 'copies values; does not duplicate them' do
119
+ expect(obj_cloned[:middleware]).to eq [middleware]
120
+ end
121
+ end
112
122
  end
113
123
  end
114
124
  end
@@ -89,6 +89,35 @@ describe Grape::Validations::ParamsScope do
89
89
  end
90
90
  end
91
91
 
92
+ context 'when using custom types' do
93
+ class CustomType
94
+ attr_reader :value
95
+ def self.parse(value)
96
+ fail if value == 'invalid'
97
+ new(value)
98
+ end
99
+
100
+ def initialize(value)
101
+ @value = value
102
+ end
103
+ end
104
+
105
+ it 'coerces the parameter via the type\'s parse method' do
106
+ subject.params do
107
+ requires :foo, type: CustomType
108
+ end
109
+ subject.get('/types') { params[:foo].value }
110
+
111
+ get '/types', foo: 'valid'
112
+ expect(last_response.status).to eq(200)
113
+ expect(last_response.body).to eq('valid')
114
+
115
+ get '/types', foo: 'invalid'
116
+ expect(last_response.status).to eq(400)
117
+ expect(last_response.body).to match(/foo is invalid/)
118
+ end
119
+ end
120
+
92
121
  context 'array without coerce type explicitly given' do
93
122
  it 'sets the type based on first element' do
94
123
  subject.params do
@@ -242,4 +271,59 @@ describe Grape::Validations::ParamsScope do
242
271
  end.to raise_error Grape::Exceptions::UnsupportedGroupTypeError
243
272
  end
244
273
  end
274
+
275
+ context 'when validations are dependent on a parameter' do
276
+ before do
277
+ subject.params do
278
+ optional :a
279
+ given :a do
280
+ requires :b
281
+ end
282
+ end
283
+ subject.get('/test') { declared(params).to_json }
284
+ end
285
+
286
+ it 'applies the validations only if the parameter is present' do
287
+ get '/test'
288
+ expect(last_response.status).to eq(200)
289
+
290
+ get '/test', a: true
291
+ expect(last_response.status).to eq(400)
292
+ expect(last_response.body).to eq('b is missing')
293
+
294
+ get '/test', a: true, b: true
295
+ expect(last_response.status).to eq(200)
296
+ end
297
+
298
+ it 'raises an error if the dependent parameter was never specified' do
299
+ expect do
300
+ subject.params do
301
+ given :c do
302
+ end
303
+ end
304
+ end.to raise_error(Grape::Exceptions::UnknownParameter)
305
+ end
306
+
307
+ it 'includes the parameter within #declared(params)' do
308
+ get '/test', a: true, b: true
309
+
310
+ expect(JSON.parse(last_response.body)).to eq('a' => 'true', 'b' => 'true')
311
+ end
312
+
313
+ it 'returns a sensible error message within a nested context' do
314
+ subject.params do
315
+ requires :bar, type: Hash do
316
+ optional :a
317
+ given :a do
318
+ requires :b
319
+ end
320
+ end
321
+ end
322
+ subject.get('/nested') { 'worked' }
323
+
324
+ get '/nested', bar: { a: true }
325
+ expect(last_response.status).to eq(400)
326
+ expect(last_response.body).to eq('bar[b] is missing')
327
+ end
328
+ end
245
329
  end
@@ -11,6 +11,14 @@ describe Grape::Validations::CoerceValidator do
11
11
  end
12
12
 
13
13
  describe 'coerce' do
14
+ module CoerceValidatorSpec
15
+ class User
16
+ include Virtus.model
17
+ attribute :id, Integer
18
+ attribute :name, String
19
+ end
20
+ end
21
+
14
22
  context 'i18n' do
15
23
  after :each do
16
24
  I18n.locale = :en
@@ -82,14 +90,6 @@ describe Grape::Validations::CoerceValidator do
82
90
  end
83
91
 
84
92
  context 'complex objects' do
85
- module CoerceValidatorSpec
86
- class User
87
- include Virtus.model
88
- attribute :id, Integer
89
- attribute :name, String
90
- end
91
- end
92
-
93
93
  it 'error on malformed input for complex objects' do
94
94
  subject.params do
95
95
  requires :user, type: CoerceValidatorSpec::User
@@ -148,6 +148,27 @@ describe Grape::Validations::CoerceValidator do
148
148
  expect(last_response.status).to eq(200)
149
149
  expect(last_response.body).to eq('TrueClass')
150
150
  end
151
+
152
+ it 'Array of Complex' do
153
+ subject.params do
154
+ requires :arry, coerce: Array[CoerceValidatorSpec::User]
155
+ end
156
+ subject.get '/array' do
157
+ params[:arry].size
158
+ end
159
+
160
+ get 'array', arry: [31]
161
+ expect(last_response.status).to eq(400)
162
+ expect(last_response.body).to eq('arry is invalid')
163
+
164
+ get 'array', arry: { id: 31, name: 'Alice' }
165
+ expect(last_response.status).to eq(400)
166
+ expect(last_response.body).to eq('arry is invalid')
167
+
168
+ get 'array', arry: [{ id: 31, name: 'Alice' }]
169
+ expect(last_response.status).to eq(200)
170
+ expect(last_response.body).to eq('1')
171
+ end
151
172
  end
152
173
 
153
174
  context 'Set' do
@@ -56,6 +56,13 @@ describe Grape::Validations::ValuesValidator do
56
56
  { type: params[:type] }
57
57
  end
58
58
 
59
+ params do
60
+ optional :type, type: Boolean, desc: 'A boolean', values: [true]
61
+ end
62
+ get '/values/optional_boolean' do
63
+ { type: params[:type] }
64
+ end
65
+
59
66
  params do
60
67
  requires :type, type: Integer, desc: 'An integer', values: [10, 11], default: 10
61
68
  end
@@ -174,6 +181,11 @@ describe Grape::Validations::ValuesValidator do
174
181
  end.to raise_error Grape::Exceptions::IncompatibleOptionValues
175
182
  end
176
183
 
184
+ it 'allows values to be true or false when setting the type to boolean' do
185
+ get('/values/optional_boolean', type: true)
186
+ expect(last_response.status).to eq 200
187
+ expect(last_response.body).to eq({ type: true }.to_json)
188
+ end
177
189
  it 'allows values to be a kind of the coerced type not just an instance of it' do
178
190
  get('/values/coercion', type: 10)
179
191
  expect(last_response.status).to eq 200
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.12.0
4
+ version: 0.13.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-06-18 00:00:00.000000000 Z
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -317,8 +317,6 @@ files:
317
317
  - gemfiles/rails_4.gemfile
318
318
  - grape.gemspec
319
319
  - grape.png
320
- - lib/backports/active_support/deep_dup.rb
321
- - lib/backports/active_support/duplicable.rb
322
320
  - lib/grape.rb
323
321
  - lib/grape/api.rb
324
322
  - lib/grape/api/helpers.rb
@@ -351,6 +349,7 @@ files:
351
349
  - lib/grape/exceptions/missing_option.rb
352
350
  - lib/grape/exceptions/missing_vendor_option.rb
353
351
  - lib/grape/exceptions/unknown_options.rb
352
+ - lib/grape/exceptions/unknown_parameter.rb
354
353
  - lib/grape/exceptions/unknown_validator.rb
355
354
  - lib/grape/exceptions/unsupported_group_type.rb
356
355
  - lib/grape/exceptions/validation.rb
@@ -385,8 +384,10 @@ files:
385
384
  - lib/grape/presenters/presenter.rb
386
385
  - lib/grape/route.rb
387
386
  - lib/grape/util/content_types.rb
387
+ - lib/grape/util/file_response.rb
388
388
  - lib/grape/util/inheritable_setting.rb
389
389
  - lib/grape/util/inheritable_values.rb
390
+ - lib/grape/util/parameter_types.rb
390
391
  - lib/grape/util/stackable_values.rb
391
392
  - lib/grape/util/strict_hash_configuration.rb
392
393
  - lib/grape/validations.rb
@@ -450,6 +451,7 @@ files:
450
451
  - spec/grape/presenters/presenter_spec.rb
451
452
  - spec/grape/util/inheritable_setting_spec.rb
452
453
  - spec/grape/util/inheritable_values_spec.rb
454
+ - spec/grape/util/parameter_types_spec.rb
453
455
  - spec/grape/util/stackable_values_spec.rb
454
456
  - spec/grape/util/strict_hash_configuration_spec.rb
455
457
  - spec/grape/validations/attributes_iterator_spec.rb
@@ -473,7 +475,7 @@ files:
473
475
  - spec/support/endpoint_faker.rb
474
476
  - spec/support/file_streamer.rb
475
477
  - spec/support/versioned_helpers.rb
476
- homepage: https://github.com/intridea/grape
478
+ homepage: https://github.com/ruby-grape/grape
477
479
  licenses:
478
480
  - MIT
479
481
  metadata: {}
@@ -492,7 +494,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
492
494
  - !ruby/object:Gem::Version
493
495
  version: '0'
494
496
  requirements: []
495
- rubyforge_project: grape
497
+ rubyforge_project:
496
498
  rubygems_version: 2.4.5
497
499
  signing_key:
498
500
  specification_version: 4
@@ -543,6 +545,7 @@ test_files:
543
545
  - spec/grape/presenters/presenter_spec.rb
544
546
  - spec/grape/util/inheritable_setting_spec.rb
545
547
  - spec/grape/util/inheritable_values_spec.rb
548
+ - spec/grape/util/parameter_types_spec.rb
546
549
  - spec/grape/util/stackable_values_spec.rb
547
550
  - spec/grape/util/strict_hash_configuration_spec.rb
548
551
  - spec/grape/validations/attributes_iterator_spec.rb
@@ -1,49 +0,0 @@
1
- # Backport from Rails 4.x
2
- # https://github.com/rails/rails/blob/4-0-stable/activesupport/lib/active_support/core_ext/object/deep_dup.rb
3
-
4
- require_relative 'duplicable'
5
-
6
- class Object
7
- # Returns a deep copy of object if it's duplicable. If it's
8
- # not duplicable, returns +self+.
9
- #
10
- # object = Object.new
11
- # dup = object.deep_dup
12
- # dup.instance_variable_set(:@a, 1)
13
- #
14
- # object.instance_variable_defined?(:@a) #=> false
15
- # dup.instance_variable_defined?(:@a) #=> true
16
- def deep_dup
17
- duplicable? ? dup : self
18
- end
19
- end
20
-
21
- class Array
22
- # Returns a deep copy of array.
23
- #
24
- # array = [1, [2, 3]]
25
- # dup = array.deep_dup
26
- # dup[1][2] = 4
27
- #
28
- # array[1][2] #=> nil
29
- # dup[1][2] #=> 4
30
- def deep_dup
31
- map(&:deep_dup)
32
- end
33
- end
34
-
35
- class Hash
36
- # Returns a deep copy of hash.
37
- #
38
- # hash = { a: { b: 'b' } }
39
- # dup = hash.deep_dup
40
- # dup[:a][:c] = 'c'
41
- #
42
- # hash[:a][:c] #=> nil
43
- # dup[:a][:c] #=> "c"
44
- def deep_dup
45
- each_with_object(dup) do |(key, value), hash|
46
- hash[key.deep_dup] = value.deep_dup
47
- end
48
- end
49
- end