grape 1.5.2 → 1.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.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +152 -21
  5. data/UPGRADING.md +86 -2
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +18 -13
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dry_types.rb +12 -0
  11. data/lib/grape/dsl/api.rb +0 -2
  12. data/lib/grape/dsl/callbacks.rb +0 -2
  13. data/lib/grape/dsl/configuration.rb +0 -2
  14. data/lib/grape/dsl/desc.rb +2 -19
  15. data/lib/grape/dsl/headers.rb +5 -2
  16. data/lib/grape/dsl/helpers.rb +7 -7
  17. data/lib/grape/dsl/inside_route.rb +43 -30
  18. data/lib/grape/dsl/middleware.rb +4 -6
  19. data/lib/grape/dsl/parameters.rb +8 -10
  20. data/lib/grape/dsl/request_response.rb +9 -8
  21. data/lib/grape/dsl/routing.rb +6 -4
  22. data/lib/grape/dsl/settings.rb +5 -7
  23. data/lib/grape/dsl/validations.rb +0 -15
  24. data/lib/grape/endpoint.rb +21 -36
  25. data/lib/grape/error_formatter/json.rb +9 -7
  26. data/lib/grape/error_formatter/xml.rb +2 -6
  27. data/lib/grape/exceptions/base.rb +2 -2
  28. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  29. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  30. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  31. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  32. data/lib/grape/exceptions/validation.rb +1 -6
  33. data/lib/grape/formatter/json.rb +1 -0
  34. data/lib/grape/formatter/serializable_hash.rb +2 -1
  35. data/lib/grape/formatter/xml.rb +1 -0
  36. data/lib/grape/locale/en.yml +9 -8
  37. data/lib/grape/middleware/auth/dsl.rb +7 -2
  38. data/lib/grape/middleware/base.rb +3 -1
  39. data/lib/grape/middleware/error.rb +2 -2
  40. data/lib/grape/middleware/formatter.rb +4 -4
  41. data/lib/grape/middleware/stack.rb +2 -2
  42. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  43. data/lib/grape/middleware/versioner/header.rb +6 -4
  44. data/lib/grape/middleware/versioner/param.rb +1 -0
  45. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  46. data/lib/grape/middleware/versioner/path.rb +2 -0
  47. data/lib/grape/parser/json.rb +1 -1
  48. data/lib/grape/parser/xml.rb +1 -1
  49. data/lib/grape/path.rb +1 -0
  50. data/lib/grape/request.rb +5 -0
  51. data/lib/grape/router/pattern.rb +1 -1
  52. data/lib/grape/router/route.rb +2 -2
  53. data/lib/grape/router.rb +6 -0
  54. data/lib/grape/util/inheritable_setting.rb +1 -3
  55. data/lib/grape/util/json.rb +2 -0
  56. data/lib/grape/util/lazy_value.rb +3 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_doc.rb +58 -0
  59. data/lib/grape/validations/params_scope.rb +137 -78
  60. data/lib/grape/validations/types/array_coercer.rb +0 -2
  61. data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
  62. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  63. data/lib/grape/validations/types/json.rb +2 -1
  64. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  65. data/lib/grape/validations/types/set_coercer.rb +0 -2
  66. data/lib/grape/validations/types.rb +98 -30
  67. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  68. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  69. data/lib/grape/validations/validators/as_validator.rb +14 -0
  70. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  71. data/lib/grape/validations/validators/base.rb +82 -70
  72. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  73. data/lib/grape/validations/validators/default_validator.rb +51 -0
  74. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  75. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  76. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  77. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  78. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  79. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  80. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  81. data/lib/grape/validations/validators/values_validator.rb +88 -0
  82. data/lib/grape/validations.rb +16 -6
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape.rb +70 -29
  85. data/spec/grape/api/custom_validations_spec.rb +116 -45
  86. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  87. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  88. data/spec/grape/api/documentation_spec.rb +59 -0
  89. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  90. data/spec/grape/api/instance_spec.rb +0 -1
  91. data/spec/grape/api/invalid_format_spec.rb +2 -2
  92. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  93. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  94. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  95. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  96. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  97. data/spec/grape/api/recognize_path_spec.rb +1 -3
  98. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  99. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  100. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  101. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  102. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  103. data/spec/grape/api_remount_spec.rb +16 -16
  104. data/spec/grape/api_spec.rb +527 -224
  105. data/spec/grape/config_spec.rb +0 -2
  106. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  107. data/spec/grape/dsl/configuration_spec.rb +0 -2
  108. data/spec/grape/dsl/desc_spec.rb +0 -2
  109. data/spec/grape/dsl/headers_spec.rb +39 -11
  110. data/spec/grape/dsl/helpers_spec.rb +3 -4
  111. data/spec/grape/dsl/inside_route_spec.rb +16 -16
  112. data/spec/grape/dsl/logger_spec.rb +15 -19
  113. data/spec/grape/dsl/middleware_spec.rb +2 -3
  114. data/spec/grape/dsl/parameters_spec.rb +2 -2
  115. data/spec/grape/dsl/request_response_spec.rb +7 -8
  116. data/spec/grape/dsl/routing_spec.rb +11 -10
  117. data/spec/grape/dsl/settings_spec.rb +0 -2
  118. data/spec/grape/dsl/validations_spec.rb +0 -17
  119. data/spec/grape/endpoint/declared_spec.rb +261 -16
  120. data/spec/grape/endpoint_spec.rb +98 -57
  121. data/spec/grape/entity_spec.rb +22 -23
  122. data/spec/grape/exceptions/base_spec.rb +16 -2
  123. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
  124. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
  125. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  126. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  127. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  128. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  129. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  130. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  131. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  132. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  133. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  134. data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
  135. data/spec/grape/exceptions/validation_spec.rb +5 -5
  136. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
  137. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
  138. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
  139. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  140. data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
  141. data/spec/grape/integration/rack_spec.rb +0 -2
  142. data/spec/grape/loading_spec.rb +8 -10
  143. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  144. data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
  145. data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
  146. data/spec/grape/middleware/base_spec.rb +24 -17
  147. data/spec/grape/middleware/error_spec.rb +8 -3
  148. data/spec/grape/middleware/exception_spec.rb +111 -163
  149. data/spec/grape/middleware/formatter_spec.rb +27 -8
  150. data/spec/grape/middleware/globals_spec.rb +7 -6
  151. data/spec/grape/middleware/stack_spec.rb +14 -14
  152. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
  153. data/spec/grape/middleware/versioner/header_spec.rb +30 -15
  154. data/spec/grape/middleware/versioner/param_spec.rb +7 -3
  155. data/spec/grape/middleware/versioner/path_spec.rb +5 -3
  156. data/spec/grape/middleware/versioner_spec.rb +1 -3
  157. data/spec/grape/named_api_spec.rb +0 -2
  158. data/spec/grape/parser_spec.rb +4 -2
  159. data/spec/grape/path_spec.rb +52 -54
  160. data/spec/grape/presenters/presenter_spec.rb +7 -8
  161. data/spec/grape/request_spec.rb +6 -6
  162. data/spec/grape/util/inheritable_setting_spec.rb +7 -8
  163. data/spec/grape/util/inheritable_values_spec.rb +3 -3
  164. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
  165. data/spec/grape/util/stackable_values_spec.rb +7 -6
  166. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  167. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  168. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  169. data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
  170. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  171. data/spec/grape/validations/params_scope_spec.rb +361 -96
  172. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  173. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  174. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  175. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  176. data/spec/grape/validations/types_spec.rb +36 -10
  177. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  178. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  179. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  180. data/spec/grape/validations/validators/coerce_spec.rb +99 -24
  181. data/spec/grape/validations/validators/default_spec.rb +72 -80
  182. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  183. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  184. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  185. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  186. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  187. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  188. data/spec/grape/validations/validators/values_spec.rb +182 -179
  189. data/spec/grape/validations_spec.rb +149 -80
  190. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  191. data/spec/integration/multi_json/json_spec.rb +1 -3
  192. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  193. data/spec/shared/versioning_examples.rb +12 -9
  194. data/spec/spec_helper.rb +21 -6
  195. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  196. metadata +125 -115
  197. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  198. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  199. data/lib/grape/validations/validators/as.rb +0 -16
  200. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  201. data/lib/grape/validations/validators/coerce.rb +0 -91
  202. data/lib/grape/validations/validators/default.rb +0 -48
  203. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  204. data/lib/grape/validations/validators/except_values.rb +0 -22
  205. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  206. data/lib/grape/validations/validators/presence.rb +0 -12
  207. data/lib/grape/validations/validators/regexp.rb +0 -13
  208. data/lib/grape/validations/validators/same_as.rb +0 -26
  209. data/lib/grape/validations/validators/values.rb +0 -83
  210. data/spec/support/eager_load.rb +0 -19
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -10,32 +8,32 @@ describe Grape::Endpoint do
10
8
  end
11
9
 
12
10
  describe '.before_each' do
13
- after { Grape::Endpoint.before_each.clear }
11
+ after { described_class.before_each.clear }
14
12
 
15
13
  it 'is settable via block' do
16
14
  block = ->(_endpoint) { 'noop' }
17
- Grape::Endpoint.before_each(&block)
18
- expect(Grape::Endpoint.before_each.first).to eq(block)
15
+ described_class.before_each(&block)
16
+ expect(described_class.before_each.first).to eq(block)
19
17
  end
20
18
 
21
19
  it 'is settable via reference' do
22
20
  block = ->(_endpoint) { 'noop' }
23
- Grape::Endpoint.before_each block
24
- expect(Grape::Endpoint.before_each.first).to eq(block)
21
+ described_class.before_each block
22
+ expect(described_class.before_each.first).to eq(block)
25
23
  end
26
24
 
27
25
  it 'is able to override a helper' do
28
26
  subject.get('/') { current_user }
29
27
  expect { get '/' }.to raise_error(NameError)
30
28
 
31
- Grape::Endpoint.before_each do |endpoint|
29
+ described_class.before_each do |endpoint|
32
30
  allow(endpoint).to receive(:current_user).and_return('Bob')
33
31
  end
34
32
 
35
33
  get '/'
36
34
  expect(last_response.body).to eq('Bob')
37
35
 
38
- Grape::Endpoint.before_each(nil)
36
+ described_class.before_each(nil)
39
37
  expect { get '/' }.to raise_error(NameError)
40
38
  end
41
39
 
@@ -46,18 +44,18 @@ describe Grape::Endpoint do
46
44
  end
47
45
  expect { get '/' }.to raise_error(NameError)
48
46
 
49
- Grape::Endpoint.before_each do |endpoint|
47
+ described_class.before_each do |endpoint|
50
48
  allow(endpoint).to receive(:current_user).and_return('Bob')
51
49
  end
52
50
 
53
- Grape::Endpoint.before_each do |endpoint|
51
+ described_class.before_each do |endpoint|
54
52
  allow(endpoint).to receive(:authenticate_user!).and_return(true)
55
53
  end
56
54
 
57
55
  get '/'
58
56
  expect(last_response.body).to eq('Bob')
59
57
 
60
- Grape::Endpoint.before_each(nil)
58
+ described_class.before_each(nil)
61
59
  expect { get '/' }.to raise_error(NameError)
62
60
  end
63
61
  end
@@ -66,7 +64,7 @@ describe Grape::Endpoint do
66
64
  it 'takes a settings stack, options, and a block' do
67
65
  p = proc {}
68
66
  expect do
69
- Grape::Endpoint.new(Grape::Util::InheritableSetting.new, {
67
+ described_class.new(Grape::Util::InheritableSetting.new, {
70
68
  path: '/',
71
69
  method: :get
72
70
  }, &p)
@@ -77,7 +75,7 @@ describe Grape::Endpoint do
77
75
  it 'sets itself in the env upon call' do
78
76
  subject.get('/') { 'Hello world.' }
79
77
  get '/'
80
- expect(last_request.env['api.endpoint']).to be_kind_of(Grape::Endpoint)
78
+ expect(last_request.env['api.endpoint']).to be_kind_of(described_class)
81
79
  end
82
80
 
83
81
  describe '#status' do
@@ -137,6 +135,7 @@ describe Grape::Endpoint do
137
135
  headers.to_json
138
136
  end
139
137
  end
138
+
140
139
  it 'includes request headers' do
141
140
  get '/headers'
142
141
  expect(JSON.parse(last_response.body)).to eq(
@@ -144,13 +143,15 @@ describe Grape::Endpoint do
144
143
  'Cookie' => ''
145
144
  )
146
145
  end
146
+
147
147
  it 'includes additional request headers' do
148
148
  get '/headers', nil, 'HTTP_X_GRAPE_CLIENT' => '1'
149
149
  expect(JSON.parse(last_response.body)['X-Grape-Client']).to eq('1')
150
150
  end
151
+
151
152
  it 'includes headers passed as symbols' do
152
153
  env = Rack::MockRequest.env_for('/headers')
153
- env['HTTP_SYMBOL_HEADER'.to_sym] = 'Goliath passes symbols'
154
+ env[:HTTP_SYMBOL_HEADER] = 'Goliath passes symbols'
154
155
  body = read_chunks(subject.call(env)[2]).join
155
156
  expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
156
157
  end
@@ -212,10 +213,10 @@ describe Grape::Endpoint do
212
213
  end
213
214
  get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
214
215
  expect(last_response.body).to eq('3')
215
- cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
216
+ cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
216
217
  cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
217
218
  [cookie.name, cookie]
218
- end]
219
+ end.to_h
219
220
  expect(cookies.size).to eq(2)
220
221
  %w[and_this delete_this_cookie].each do |cookie_name|
221
222
  cookie = cookies[cookie_name]
@@ -236,10 +237,10 @@ describe Grape::Endpoint do
236
237
  end
237
238
  get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
238
239
  expect(last_response.body).to eq('3')
239
- cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
240
+ cookies = last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
240
241
  cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
241
242
  [cookie.name, cookie]
242
- end]
243
+ end.to_h
243
244
  expect(cookies.size).to eq(2)
244
245
  %w[and_this delete_this_cookie].each do |cookie_name|
245
246
  cookie = cookies[cookie_name]
@@ -253,7 +254,7 @@ describe Grape::Endpoint do
253
254
 
254
255
  describe '#params' do
255
256
  context 'default class' do
256
- it 'should be a ActiveSupport::HashWithIndifferentAccess' do
257
+ it 'is a ActiveSupport::HashWithIndifferentAccess' do
257
258
  subject.get '/foo' do
258
259
  params.class
259
260
  end
@@ -339,7 +340,7 @@ describe Grape::Endpoint do
339
340
  end
340
341
 
341
342
  context 'namespace requirements' do
342
- before :each do
343
+ before do
343
344
  subject.namespace :outer, requirements: { person_email: /abc@(.*).com/ } do
344
345
  get('/:person_email') do
345
346
  params[:person_email]
@@ -358,7 +359,7 @@ describe Grape::Endpoint do
358
359
  expect(last_response.body).to eq('abc@example.com')
359
360
  end
360
361
 
361
- it "should override outer namespace's requirements" do
362
+ it "overrides outer namespace's requirements" do
362
363
  get '/outer/inner/someone@testing.wrong/test/1'
363
364
  expect(last_response.status).to eq(404)
364
365
 
@@ -370,7 +371,7 @@ describe Grape::Endpoint do
370
371
  end
371
372
 
372
373
  context 'from body parameters' do
373
- before(:each) do
374
+ before do
374
375
  subject.post '/request_body' do
375
376
  params[:user]
376
377
  end
@@ -420,6 +421,40 @@ describe Grape::Endpoint do
420
421
  expect(last_response.status).to eq(201)
421
422
  expect(last_response.body).to eq('Bob')
422
423
  end
424
+
425
+ # Rack swallowed this error until v2.2.0
426
+ it 'returns a 400 if given an invalid multipart body', if: Gem::Version.new(Rack.release) >= Gem::Version.new('2.2.0') do
427
+ subject.params do
428
+ requires :file, type: Rack::Multipart::UploadedFile
429
+ end
430
+ subject.post '/upload' do
431
+ params[:file][:filename]
432
+ end
433
+ post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
434
+ expect(last_response.status).to eq(400)
435
+ expect(last_response.body).to eq('empty message body supplied with multipart/form-data; boundary=foobar content-type')
436
+ end
437
+ end
438
+
439
+ context 'when the limit on multipart files is exceeded' do
440
+ around do |example|
441
+ limit = Rack::Utils.multipart_part_limit
442
+ Rack::Utils.multipart_part_limit = 1
443
+ example.run
444
+ Rack::Utils.multipart_part_limit = limit
445
+ end
446
+
447
+ it 'returns a 413 if given too many multipart files' do
448
+ subject.params do
449
+ requires :file, type: Rack::Multipart::UploadedFile
450
+ end
451
+ subject.post '/upload' do
452
+ params[:file][:filename]
453
+ end
454
+ post '/upload', { file: Rack::Test::UploadedFile.new(__FILE__, 'text/plain'), extra: Rack::Test::UploadedFile.new(__FILE__, 'text/plain') }
455
+ expect(last_response.status).to eq(413)
456
+ expect(last_response.body).to eq("the number of uploaded files exceeded the system's configured limit (1)")
457
+ end
423
458
  end
424
459
 
425
460
  it 'responds with a 415 for an unsupported content-type' do
@@ -456,11 +491,11 @@ describe Grape::Endpoint do
456
491
  post '/', ::Grape::Json.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
457
492
  end
458
493
 
459
- it 'should not response with 406 for same type without params' do
494
+ it 'does not response with 406 for same type without params' do
460
495
  expect(last_response.status).not_to be 406
461
496
  end
462
497
 
463
- it 'should response with given content type in headers' do
498
+ it 'responses with given content type in headers' do
464
499
  expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
465
500
  end
466
501
  end
@@ -696,16 +731,18 @@ describe Grape::Endpoint do
696
731
  describe '.generate_api_method' do
697
732
  it 'raises NameError if the method name is already in use' do
698
733
  expect do
699
- Grape::Endpoint.generate_api_method('version', &proc {})
734
+ described_class.generate_api_method('version', &proc {})
700
735
  end.to raise_error(NameError)
701
736
  end
737
+
702
738
  it 'raises ArgumentError if a block is not given' do
703
739
  expect do
704
- Grape::Endpoint.generate_api_method('GET without a block method')
740
+ described_class.generate_api_method('GET without a block method')
705
741
  end.to raise_error(ArgumentError)
706
742
  end
743
+
707
744
  it 'returns a Proc' do
708
- expect(Grape::Endpoint.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
745
+ expect(described_class.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
709
746
  end
710
747
  end
711
748
 
@@ -764,7 +801,7 @@ describe Grape::Endpoint do
764
801
  end
765
802
 
766
803
  get '/error_filters'
767
- expect(last_response.status).to eql 500
804
+ expect(last_response.status).to be 500
768
805
  expect(called).to match_array %w[before before_validation]
769
806
  end
770
807
 
@@ -773,8 +810,11 @@ describe Grape::Endpoint do
773
810
  subject.before { called << 'parent' }
774
811
  subject.namespace :parent do
775
812
  before { called << 'prior' }
813
+
776
814
  before { error! :oops, 500 }
815
+
777
816
  before { called << 'subsequent' }
817
+
778
818
  get :hello do
779
819
  called << :endpoint
780
820
  'Hello!'
@@ -782,7 +822,7 @@ describe Grape::Endpoint do
782
822
  end
783
823
 
784
824
  get '/parent/hello'
785
- expect(last_response.status).to eql 500
825
+ expect(last_response.status).to be 500
786
826
  expect(called).to match_array %w[parent prior]
787
827
  end
788
828
  end
@@ -793,19 +833,19 @@ describe Grape::Endpoint do
793
833
  it 'allows for the anchoring option with a delete method' do
794
834
  subject.send(:delete, '/example', anchor: true) {}
795
835
  send(:delete, '/example/and/some/more')
796
- expect(last_response.status).to eql 404
836
+ expect(last_response.status).to be 404
797
837
  end
798
838
 
799
839
  it 'anchors paths by default for the delete method' do
800
840
  subject.send(:delete, '/example') {}
801
841
  send(:delete, '/example/and/some/more')
802
- expect(last_response.status).to eql 404
842
+ expect(last_response.status).to be 404
803
843
  end
804
844
 
805
845
  it 'responds to /example/and/some/more for the non-anchored delete method' do
806
846
  subject.send(:delete, '/example', anchor: false) {}
807
847
  send(:delete, '/example/and/some/more')
808
- expect(last_response.status).to eql 204
848
+ expect(last_response.status).to be 204
809
849
  expect(last_response.body).to be_empty
810
850
  end
811
851
  end
@@ -817,7 +857,7 @@ describe Grape::Endpoint do
817
857
  body 'deleted'
818
858
  end
819
859
  send(:delete, '/example/and/some/more')
820
- expect(last_response.status).to eql 200
860
+ expect(last_response.status).to be 200
821
861
  expect(last_response.body).not_to be_empty
822
862
  end
823
863
  end
@@ -826,7 +866,7 @@ describe Grape::Endpoint do
826
866
  it 'responds to /example delete method' do
827
867
  subject.delete(:example) { 'deleted' }
828
868
  delete '/example'
829
- expect(last_response.status).to eql 200
869
+ expect(last_response.status).to be 200
830
870
  expect(last_response.body).not_to be_empty
831
871
  end
832
872
  end
@@ -835,7 +875,7 @@ describe Grape::Endpoint do
835
875
  it 'responds to /example delete method' do
836
876
  subject.delete(:example) { nil }
837
877
  delete '/example'
838
- expect(last_response.status).to eql 204
878
+ expect(last_response.status).to be 204
839
879
  expect(last_response.body).to be_empty
840
880
  end
841
881
  end
@@ -844,7 +884,7 @@ describe Grape::Endpoint do
844
884
  it 'responds to /example delete method' do
845
885
  subject.delete(:example) { '' }
846
886
  delete '/example'
847
- expect(last_response.status).to eql 204
887
+ expect(last_response.status).to be 204
848
888
  expect(last_response.body).to be_empty
849
889
  end
850
890
  end
@@ -856,7 +896,7 @@ describe Grape::Endpoint do
856
896
  verb
857
897
  end
858
898
  send(verb, '/example/and/some/more')
859
- expect(last_response.status).to eql 404
899
+ expect(last_response.status).to be 404
860
900
  end
861
901
 
862
902
  it "anchors paths by default for the #{verb.upcase} method" do
@@ -864,7 +904,7 @@ describe Grape::Endpoint do
864
904
  verb
865
905
  end
866
906
  send(verb, '/example/and/some/more')
867
- expect(last_response.status).to eql 404
907
+ expect(last_response.status).to be 404
868
908
  end
869
909
 
870
910
  it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do
@@ -887,8 +927,9 @@ describe Grape::Endpoint do
887
927
  get '/url'
888
928
  expect(last_response.body).to eq('http://example.org/url')
889
929
  end
930
+
890
931
  ['v1', :v1].each do |version|
891
- it "should include version #{version}" do
932
+ it "includes version #{version}" do
892
933
  subject.version version, using: :path
893
934
  subject.get('/url') do
894
935
  request.url
@@ -897,7 +938,7 @@ describe Grape::Endpoint do
897
938
  expect(last_response.body).to eq("http://example.org/#{version}/url")
898
939
  end
899
940
  end
900
- it 'should include prefix' do
941
+ it 'includes prefix' do
901
942
  subject.version 'v1', using: :path
902
943
  subject.prefix 'api'
903
944
  subject.get('/url') do
@@ -987,26 +1028,26 @@ describe Grape::Endpoint do
987
1028
 
988
1029
  # In order that the events finalized (time each block ended)
989
1030
  expect(@events).to contain_exactly(
990
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1031
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
991
1032
  filters: a_collection_containing_exactly(an_instance_of(Proc)),
992
1033
  type: :before }),
993
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1034
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
994
1035
  filters: [],
995
1036
  type: :before_validation }),
996
- have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1037
+ have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
997
1038
  validators: [],
998
1039
  request: a_kind_of(Grape::Request) }),
999
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1040
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1000
1041
  filters: [],
1001
1042
  type: :after_validation }),
1002
- have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(Grape::Endpoint) }),
1003
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1043
+ have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
1044
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1004
1045
  filters: [],
1005
1046
  type: :after }),
1006
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1047
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1007
1048
  filters: [],
1008
1049
  type: :finally }),
1009
- have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1050
+ have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
1010
1051
  env: an_instance_of(Hash) }),
1011
1052
  have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
1012
1053
  formatter: a_kind_of(Module) })
@@ -1014,25 +1055,25 @@ describe Grape::Endpoint do
1014
1055
 
1015
1056
  # In order that events were initialized
1016
1057
  expect(@events.sort_by(&:time)).to contain_exactly(
1017
- have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1058
+ have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
1018
1059
  env: an_instance_of(Hash) }),
1019
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1060
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1020
1061
  filters: a_collection_containing_exactly(an_instance_of(Proc)),
1021
1062
  type: :before }),
1022
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1063
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1023
1064
  filters: [],
1024
1065
  type: :before_validation }),
1025
- have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1066
+ have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
1026
1067
  validators: [],
1027
1068
  request: a_kind_of(Grape::Request) }),
1028
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1069
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1029
1070
  filters: [],
1030
1071
  type: :after_validation }),
1031
- have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(Grape::Endpoint) }),
1032
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1072
+ have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
1073
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1033
1074
  filters: [],
1034
1075
  type: :after }),
1035
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1076
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1036
1077
  filters: [],
1037
1078
  type: :finally }),
1038
1079
  have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
3
  require 'grape_entity'
5
4
 
6
5
  describe Grape::Entity do
@@ -32,7 +31,7 @@ describe Grape::Entity do
32
31
  end
33
32
 
34
33
  it 'pulls a representation from the class options if it exists' do
35
- entity = Class.new(Grape::Entity)
34
+ entity = Class.new(described_class)
36
35
  allow(entity).to receive(:represent).and_return('Hiya')
37
36
 
38
37
  subject.represent Object, with: entity
@@ -44,7 +43,7 @@ describe Grape::Entity do
44
43
  end
45
44
 
46
45
  it 'pulls a representation from the class options if the presented object is a collection of objects' do
47
- entity = Class.new(Grape::Entity)
46
+ entity = Class.new(described_class)
48
47
  allow(entity).to receive(:represent).and_return('Hiya')
49
48
 
50
49
  module EntitySpec
@@ -75,7 +74,7 @@ describe Grape::Entity do
75
74
  end
76
75
 
77
76
  it 'pulls a representation from the class ancestor if it exists' do
78
- entity = Class.new(Grape::Entity)
77
+ entity = Class.new(described_class)
79
78
  allow(entity).to receive(:represent).and_return('Hiya')
80
79
 
81
80
  subclass = Class.new(Object)
@@ -90,7 +89,7 @@ describe Grape::Entity do
90
89
 
91
90
  it 'automatically uses Klass::Entity if that exists' do
92
91
  some_model = Class.new
93
- entity = Class.new(Grape::Entity)
92
+ entity = Class.new(described_class)
94
93
  allow(entity).to receive(:represent).and_return('Auto-detect!')
95
94
 
96
95
  some_model.const_set :Entity, entity
@@ -104,7 +103,7 @@ describe Grape::Entity do
104
103
 
105
104
  it 'automatically uses Klass::Entity based on the first object in the collection being presented' do
106
105
  some_model = Class.new
107
- entity = Class.new(Grape::Entity)
106
+ entity = Class.new(described_class)
108
107
  allow(entity).to receive(:represent).and_return('Auto-detect!')
109
108
 
110
109
  some_model.const_set :Entity, entity
@@ -117,7 +116,7 @@ describe Grape::Entity do
117
116
  end
118
117
 
119
118
  it 'does not run autodetection for Entity when explicitly provided' do
120
- entity = Class.new(Grape::Entity)
119
+ entity = Class.new(described_class)
121
120
  some_array = []
122
121
 
123
122
  subject.get '/example' do
@@ -129,7 +128,7 @@ describe Grape::Entity do
129
128
  end
130
129
 
131
130
  it 'does not use #first method on ActiveRecord::Relation to prevent needless sql query' do
132
- entity = Class.new(Grape::Entity)
131
+ entity = Class.new(described_class)
133
132
  some_relation = Class.new
134
133
  some_model = Class.new
135
134
 
@@ -173,7 +172,7 @@ describe Grape::Entity do
173
172
 
174
173
  %i[json serializable_hash].each do |format|
175
174
  it "presents with #{format}" do
176
- entity = Class.new(Grape::Entity)
175
+ entity = Class.new(described_class)
177
176
  entity.root 'examples', 'example'
178
177
  entity.expose :id
179
178
 
@@ -195,7 +194,7 @@ describe Grape::Entity do
195
194
  end
196
195
 
197
196
  it "presents with #{format} collection" do
198
- entity = Class.new(Grape::Entity)
197
+ entity = Class.new(described_class)
199
198
  entity.root 'examples', 'example'
200
199
  entity.expose :id
201
200
 
@@ -219,7 +218,7 @@ describe Grape::Entity do
219
218
  end
220
219
 
221
220
  it 'presents with xml' do
222
- entity = Class.new(Grape::Entity)
221
+ entity = Class.new(described_class)
223
222
  entity.root 'examples', 'example'
224
223
  entity.expose :name
225
224
 
@@ -238,18 +237,18 @@ describe Grape::Entity do
238
237
  get '/example'
239
238
  expect(last_response.status).to eq(200)
240
239
  expect(last_response.headers['Content-type']).to eq('application/xml')
241
- expect(last_response.body).to eq <<-XML
242
- <?xml version="1.0" encoding="UTF-8"?>
243
- <hash>
244
- <example>
245
- <name>johnnyiller</name>
246
- </example>
247
- </hash>
248
- XML
240
+ expect(last_response.body).to eq <<~XML
241
+ <?xml version="1.0" encoding="UTF-8"?>
242
+ <hash>
243
+ <example>
244
+ <name>johnnyiller</name>
245
+ </example>
246
+ </hash>
247
+ XML
249
248
  end
250
249
 
251
250
  it 'presents with json' do
252
- entity = Class.new(Grape::Entity)
251
+ entity = Class.new(described_class)
253
252
  entity.root 'examples', 'example'
254
253
  entity.expose :name
255
254
 
@@ -275,7 +274,7 @@ XML
275
274
  # Include JSONP middleware
276
275
  subject.use Rack::JSONP
277
276
 
278
- entity = Class.new(Grape::Entity)
277
+ entity = Class.new(described_class)
279
278
  entity.root 'examples', 'example'
280
279
  entity.expose :name
281
280
 
@@ -315,7 +314,7 @@ XML
315
314
  user1 = user.new(name: 'user1')
316
315
  user2 = user.new(name: 'user2')
317
316
 
318
- entity = Class.new(Grape::Entity)
317
+ entity = Class.new(described_class)
319
318
  entity.expose :name
320
319
 
321
320
  subject.format :json
@@ -326,7 +325,7 @@ XML
326
325
  end
327
326
  get '/example'
328
327
  expect_response_json = {
329
- 'page' => 1,
328
+ 'page' => 1,
330
329
  'user1' => { 'name' => 'user1' },
331
330
  'user2' => { 'name' => 'user2' }
332
331
  }
@@ -1,8 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Exceptions::Base do
4
+ describe '#to_s' do
5
+ subject { described_class.new(message: message).to_s }
6
+
7
+ let(:message) { 'a_message' }
8
+
9
+ it { is_expected.to eq(message) }
10
+ end
11
+
12
+ describe '#message' do
13
+ subject { described_class.new(message: message).message }
14
+
15
+ let(:message) { 'a_message' }
16
+
17
+ it { is_expected.to eq(message) }
18
+ end
19
+
6
20
  describe '#compose_message' do
7
21
  subject { described_class.new.send(:compose_message, key, **attributes) }
8
22
 
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Exceptions::ValidationErrors do
6
4
  context 'api with rescue_from :all handler' do
7
5
  subject { Class.new(Grape::API) }
6
+
8
7
  before do
9
8
  subject.rescue_from :all do |_e|
10
9
  rack_response 'message was processed', 400
@@ -56,6 +55,7 @@ describe Grape::Exceptions::ValidationErrors do
56
55
 
57
56
  context 'api with rescue_from :grape_exceptions handler' do
58
57
  subject { Class.new(Grape::API) }
58
+
59
59
  before do
60
60
  subject.rescue_from :all do |_e|
61
61
  rack_response 'message was processed', 400
@@ -93,6 +93,7 @@ describe Grape::Exceptions::ValidationErrors do
93
93
 
94
94
  context 'api without a rescue handler' do
95
95
  subject { Class.new(Grape::API) }
96
+
96
97
  before do
97
98
  subject.params do
98
99
  requires :beer