grape 1.5.3 → 1.7.1

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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/CONTRIBUTING.md +32 -1
  4. data/README.md +176 -25
  5. data/UPGRADING.md +61 -4
  6. data/grape.gemspec +6 -6
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +17 -12
  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 +4 -20
  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 +13 -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 +22 -37
  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 +3 -2
  28. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  29. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  30. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  31. data/lib/grape/exceptions/validation.rb +1 -6
  32. data/lib/grape/formatter/json.rb +1 -0
  33. data/lib/grape/formatter/serializable_hash.rb +2 -1
  34. data/lib/grape/formatter/xml.rb +1 -0
  35. data/lib/grape/locale/en.yml +9 -8
  36. data/lib/grape/middleware/auth/dsl.rb +7 -2
  37. data/lib/grape/middleware/base.rb +3 -1
  38. data/lib/grape/middleware/error.rb +2 -2
  39. data/lib/grape/middleware/formatter.rb +4 -4
  40. data/lib/grape/middleware/stack.rb +3 -3
  41. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  42. data/lib/grape/middleware/versioner/header.rb +6 -4
  43. data/lib/grape/middleware/versioner/param.rb +1 -0
  44. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  45. data/lib/grape/middleware/versioner/path.rb +2 -0
  46. data/lib/grape/path.rb +1 -0
  47. data/lib/grape/request.rb +4 -1
  48. data/lib/grape/router/attribute_translator.rb +1 -1
  49. data/lib/grape/router/pattern.rb +1 -1
  50. data/lib/grape/router/route.rb +2 -2
  51. data/lib/grape/router.rb +6 -0
  52. data/lib/grape/types/invalid_value.rb +8 -0
  53. data/lib/grape/util/cache.rb +1 -1
  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 +138 -79
  60. data/lib/grape/validations/types/array_coercer.rb +0 -2
  61. data/lib/grape/validations/types/custom_type_coercer.rb +1 -0
  62. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  63. data/lib/grape/validations/types/invalid_value.rb +0 -7
  64. data/lib/grape/validations/types/json.rb +2 -1
  65. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  66. data/lib/grape/validations/types/set_coercer.rb +0 -2
  67. data/lib/grape/validations/types.rb +98 -30
  68. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  69. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  70. data/lib/grape/validations/validators/as_validator.rb +14 -0
  71. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  72. data/lib/grape/validations/validators/base.rb +82 -70
  73. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  74. data/lib/grape/validations/validators/default_validator.rb +51 -0
  75. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  76. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  77. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  78. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  79. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  80. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  81. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  82. data/lib/grape/validations/validators/values_validator.rb +88 -0
  83. data/lib/grape/validations.rb +16 -6
  84. data/lib/grape/version.rb +1 -1
  85. data/lib/grape.rb +77 -29
  86. data/spec/grape/api/custom_validations_spec.rb +116 -45
  87. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  88. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  89. data/spec/grape/api/documentation_spec.rb +59 -0
  90. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  91. data/spec/grape/api/instance_spec.rb +0 -1
  92. data/spec/grape/api/invalid_format_spec.rb +2 -2
  93. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  94. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  95. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  96. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  97. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  98. data/spec/grape/api/recognize_path_spec.rb +1 -3
  99. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  100. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  101. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  102. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  103. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  104. data/spec/grape/api_remount_spec.rb +16 -16
  105. data/spec/grape/api_spec.rb +462 -251
  106. data/spec/grape/config_spec.rb +0 -2
  107. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  108. data/spec/grape/dsl/desc_spec.rb +2 -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 +88 -59
  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 +64 -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 +6 -7
  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 +28 -19
  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 +33 -14
  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/instance_behaivour_spec.rb +9 -12
  169. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  170. data/spec/grape/validations/params_scope_spec.rb +361 -96
  171. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  172. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  173. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  174. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  175. data/spec/grape/validations/types_spec.rb +36 -10
  176. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  177. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  178. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  179. data/spec/grape/validations/validators/coerce_spec.rb +23 -24
  180. data/spec/grape/validations/validators/default_spec.rb +72 -80
  181. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  182. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  183. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  184. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  185. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  186. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  187. data/spec/grape/validations/validators/values_spec.rb +201 -179
  188. data/spec/grape/validations_spec.rb +171 -79
  189. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  190. data/spec/integration/multi_json/json_spec.rb +1 -3
  191. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  192. data/spec/shared/versioning_examples.rb +12 -9
  193. data/spec/spec_helper.rb +21 -6
  194. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  195. metadata +41 -29
  196. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  197. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  198. data/lib/grape/validations/validators/as.rb +0 -16
  199. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  200. data/lib/grape/validations/validators/coerce.rb +0 -91
  201. data/lib/grape/validations/validators/default.rb +0 -48
  202. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  203. data/lib/grape/validations/validators/except_values.rb +0 -22
  204. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  205. data/lib/grape/validations/validators/presence.rb +0 -12
  206. data/lib/grape/validations/validators/regexp.rb +0 -13
  207. data/lib/grape/validations/validators/same_as.rb +0 -26
  208. data/lib/grape/validations/validators/values.rb +0 -83
  209. data/spec/grape/dsl/configuration_spec.rb +0 -16
  210. data/spec/grape/validations/attributes_iterator_spec.rb +0 -6
  211. 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_a(described_class)
81
79
  end
82
80
 
83
81
  describe '#status' do
@@ -137,20 +135,24 @@ 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(
143
142
  'Host' => 'example.org',
144
- 'Cookie' => ''
143
+ 'Cookie' => '',
144
+ 'Version' => 'HTTP/1.0'
145
145
  )
146
146
  end
147
+
147
148
  it 'includes additional request headers' do
148
149
  get '/headers', nil, 'HTTP_X_GRAPE_CLIENT' => '1'
149
150
  expect(JSON.parse(last_response.body)['X-Grape-Client']).to eq('1')
150
151
  end
152
+
151
153
  it 'includes headers passed as symbols' do
152
154
  env = Rack::MockRequest.env_for('/headers')
153
- env['HTTP_SYMBOL_HEADER'.to_sym] = 'Goliath passes symbols'
155
+ env[:HTTP_SYMBOL_HEADER] = 'Goliath passes symbols'
154
156
  body = read_chunks(subject.call(env)[2]).join
155
157
  expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols')
156
158
  end
@@ -212,10 +214,10 @@ describe Grape::Endpoint do
212
214
  end
213
215
  get '/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2'
214
216
  expect(last_response.body).to eq('3')
215
- cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
217
+ cookies = last_response.headers['Set-Cookie'].split("\n").to_h do |set_cookie|
216
218
  cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
217
219
  [cookie.name, cookie]
218
- end]
220
+ end
219
221
  expect(cookies.size).to eq(2)
220
222
  %w[and_this delete_this_cookie].each do |cookie_name|
221
223
  cookie = cookies[cookie_name]
@@ -236,10 +238,10 @@ describe Grape::Endpoint do
236
238
  end
237
239
  get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
238
240
  expect(last_response.body).to eq('3')
239
- cookies = Hash[last_response.headers['Set-Cookie'].split("\n").map do |set_cookie|
241
+ cookies = last_response.headers['Set-Cookie'].split("\n").to_h do |set_cookie|
240
242
  cookie = CookieJar::Cookie.from_set_cookie 'http://localhost/test', set_cookie
241
243
  [cookie.name, cookie]
242
- end]
244
+ end
243
245
  expect(cookies.size).to eq(2)
244
246
  %w[and_this delete_this_cookie].each do |cookie_name|
245
247
  cookie = cookies[cookie_name]
@@ -253,7 +255,7 @@ describe Grape::Endpoint do
253
255
 
254
256
  describe '#params' do
255
257
  context 'default class' do
256
- it 'should be a ActiveSupport::HashWithIndifferentAccess' do
258
+ it 'is a ActiveSupport::HashWithIndifferentAccess' do
257
259
  subject.get '/foo' do
258
260
  params.class
259
261
  end
@@ -339,7 +341,7 @@ describe Grape::Endpoint do
339
341
  end
340
342
 
341
343
  context 'namespace requirements' do
342
- before :each do
344
+ before do
343
345
  subject.namespace :outer, requirements: { person_email: /abc@(.*).com/ } do
344
346
  get('/:person_email') do
345
347
  params[:person_email]
@@ -358,7 +360,7 @@ describe Grape::Endpoint do
358
360
  expect(last_response.body).to eq('abc@example.com')
359
361
  end
360
362
 
361
- it "should override outer namespace's requirements" do
363
+ it "overrides outer namespace's requirements" do
362
364
  get '/outer/inner/someone@testing.wrong/test/1'
363
365
  expect(last_response.status).to eq(404)
364
366
 
@@ -370,7 +372,7 @@ describe Grape::Endpoint do
370
372
  end
371
373
 
372
374
  context 'from body parameters' do
373
- before(:each) do
375
+ before do
374
376
  subject.post '/request_body' do
375
377
  params[:user]
376
378
  end
@@ -431,7 +433,28 @@ describe Grape::Endpoint do
431
433
  end
432
434
  post '/upload', { file: '' }, 'CONTENT_TYPE' => 'multipart/form-data; boundary=foobar'
433
435
  expect(last_response.status).to eq(400)
434
- expect(last_response.body).to eq('Empty message body supplied with multipart/form-data; boundary=foobar content-type')
436
+ expect(last_response.body).to eq('file is invalid')
437
+ end
438
+ end
439
+
440
+ context 'when the limit on multipart files is exceeded' do
441
+ around do |example|
442
+ limit = Rack::Utils.multipart_part_limit
443
+ Rack::Utils.multipart_part_limit = 1
444
+ example.run
445
+ Rack::Utils.multipart_part_limit = limit
446
+ end
447
+
448
+ it 'returns a 413 if given too many multipart files' do
449
+ subject.params do
450
+ requires :file, type: Rack::Multipart::UploadedFile
451
+ end
452
+ subject.post '/upload' do
453
+ params[:file][:filename]
454
+ end
455
+ post '/upload', { file: Rack::Test::UploadedFile.new(__FILE__, 'text/plain'), extra: Rack::Test::UploadedFile.new(__FILE__, 'text/plain') }
456
+ expect(last_response.status).to eq(413)
457
+ expect(last_response.body).to eq("the number of uploaded files exceeded the system's configured limit (1)")
435
458
  end
436
459
  end
437
460
 
@@ -469,11 +492,11 @@ describe Grape::Endpoint do
469
492
  post '/', ::Grape::Json.dump(data: { some: 'payload' }), 'CONTENT_TYPE' => 'application/json'
470
493
  end
471
494
 
472
- it 'should not response with 406 for same type without params' do
495
+ it 'does not response with 406 for same type without params' do
473
496
  expect(last_response.status).not_to be 406
474
497
  end
475
498
 
476
- it 'should response with given content type in headers' do
499
+ it 'responses with given content type in headers' do
477
500
  expect(last_response.headers['Content-Type']).to eq 'application/json; charset=utf-8'
478
501
  end
479
502
  end
@@ -709,16 +732,18 @@ describe Grape::Endpoint do
709
732
  describe '.generate_api_method' do
710
733
  it 'raises NameError if the method name is already in use' do
711
734
  expect do
712
- Grape::Endpoint.generate_api_method('version', &proc {})
735
+ described_class.generate_api_method('version', &proc {})
713
736
  end.to raise_error(NameError)
714
737
  end
738
+
715
739
  it 'raises ArgumentError if a block is not given' do
716
740
  expect do
717
- Grape::Endpoint.generate_api_method('GET without a block method')
741
+ described_class.generate_api_method('GET without a block method')
718
742
  end.to raise_error(ArgumentError)
719
743
  end
744
+
720
745
  it 'returns a Proc' do
721
- expect(Grape::Endpoint.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
746
+ expect(described_class.generate_api_method('GET test for a proc', &proc {})).to be_a Proc
722
747
  end
723
748
  end
724
749
 
@@ -777,7 +802,7 @@ describe Grape::Endpoint do
777
802
  end
778
803
 
779
804
  get '/error_filters'
780
- expect(last_response.status).to eql 500
805
+ expect(last_response.status).to be 500
781
806
  expect(called).to match_array %w[before before_validation]
782
807
  end
783
808
 
@@ -786,8 +811,11 @@ describe Grape::Endpoint do
786
811
  subject.before { called << 'parent' }
787
812
  subject.namespace :parent do
788
813
  before { called << 'prior' }
814
+
789
815
  before { error! :oops, 500 }
816
+
790
817
  before { called << 'subsequent' }
818
+
791
819
  get :hello do
792
820
  called << :endpoint
793
821
  'Hello!'
@@ -795,7 +823,7 @@ describe Grape::Endpoint do
795
823
  end
796
824
 
797
825
  get '/parent/hello'
798
- expect(last_response.status).to eql 500
826
+ expect(last_response.status).to be 500
799
827
  expect(called).to match_array %w[parent prior]
800
828
  end
801
829
  end
@@ -806,19 +834,19 @@ describe Grape::Endpoint do
806
834
  it 'allows for the anchoring option with a delete method' do
807
835
  subject.send(:delete, '/example', anchor: true) {}
808
836
  send(:delete, '/example/and/some/more')
809
- expect(last_response.status).to eql 404
837
+ expect(last_response.status).to be 404
810
838
  end
811
839
 
812
840
  it 'anchors paths by default for the delete method' do
813
841
  subject.send(:delete, '/example') {}
814
842
  send(:delete, '/example/and/some/more')
815
- expect(last_response.status).to eql 404
843
+ expect(last_response.status).to be 404
816
844
  end
817
845
 
818
846
  it 'responds to /example/and/some/more for the non-anchored delete method' do
819
847
  subject.send(:delete, '/example', anchor: false) {}
820
848
  send(:delete, '/example/and/some/more')
821
- expect(last_response.status).to eql 204
849
+ expect(last_response.status).to be 204
822
850
  expect(last_response.body).to be_empty
823
851
  end
824
852
  end
@@ -830,7 +858,7 @@ describe Grape::Endpoint do
830
858
  body 'deleted'
831
859
  end
832
860
  send(:delete, '/example/and/some/more')
833
- expect(last_response.status).to eql 200
861
+ expect(last_response.status).to be 200
834
862
  expect(last_response.body).not_to be_empty
835
863
  end
836
864
  end
@@ -839,7 +867,7 @@ describe Grape::Endpoint do
839
867
  it 'responds to /example delete method' do
840
868
  subject.delete(:example) { 'deleted' }
841
869
  delete '/example'
842
- expect(last_response.status).to eql 200
870
+ expect(last_response.status).to be 200
843
871
  expect(last_response.body).not_to be_empty
844
872
  end
845
873
  end
@@ -848,7 +876,7 @@ describe Grape::Endpoint do
848
876
  it 'responds to /example delete method' do
849
877
  subject.delete(:example) { nil }
850
878
  delete '/example'
851
- expect(last_response.status).to eql 204
879
+ expect(last_response.status).to be 204
852
880
  expect(last_response.body).to be_empty
853
881
  end
854
882
  end
@@ -857,7 +885,7 @@ describe Grape::Endpoint do
857
885
  it 'responds to /example delete method' do
858
886
  subject.delete(:example) { '' }
859
887
  delete '/example'
860
- expect(last_response.status).to eql 204
888
+ expect(last_response.status).to be 204
861
889
  expect(last_response.body).to be_empty
862
890
  end
863
891
  end
@@ -869,7 +897,7 @@ describe Grape::Endpoint do
869
897
  verb
870
898
  end
871
899
  send(verb, '/example/and/some/more')
872
- expect(last_response.status).to eql 404
900
+ expect(last_response.status).to be 404
873
901
  end
874
902
 
875
903
  it "anchors paths by default for the #{verb.upcase} method" do
@@ -877,7 +905,7 @@ describe Grape::Endpoint do
877
905
  verb
878
906
  end
879
907
  send(verb, '/example/and/some/more')
880
- expect(last_response.status).to eql 404
908
+ expect(last_response.status).to be 404
881
909
  end
882
910
 
883
911
  it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do
@@ -900,8 +928,9 @@ describe Grape::Endpoint do
900
928
  get '/url'
901
929
  expect(last_response.body).to eq('http://example.org/url')
902
930
  end
931
+
903
932
  ['v1', :v1].each do |version|
904
- it "should include version #{version}" do
933
+ it "includes version #{version}" do
905
934
  subject.version version, using: :path
906
935
  subject.get('/url') do
907
936
  request.url
@@ -910,7 +939,7 @@ describe Grape::Endpoint do
910
939
  expect(last_response.body).to eq("http://example.org/#{version}/url")
911
940
  end
912
941
  end
913
- it 'should include prefix' do
942
+ it 'includes prefix' do
914
943
  subject.version 'v1', using: :path
915
944
  subject.prefix 'api'
916
945
  subject.get('/url') do
@@ -1000,26 +1029,26 @@ describe Grape::Endpoint do
1000
1029
 
1001
1030
  # In order that the events finalized (time each block ended)
1002
1031
  expect(@events).to contain_exactly(
1003
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1032
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1004
1033
  filters: a_collection_containing_exactly(an_instance_of(Proc)),
1005
1034
  type: :before }),
1006
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1035
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1007
1036
  filters: [],
1008
1037
  type: :before_validation }),
1009
- have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1038
+ have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
1010
1039
  validators: [],
1011
1040
  request: a_kind_of(Grape::Request) }),
1012
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1041
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1013
1042
  filters: [],
1014
1043
  type: :after_validation }),
1015
- have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(Grape::Endpoint) }),
1016
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1044
+ have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
1045
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1017
1046
  filters: [],
1018
1047
  type: :after }),
1019
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1048
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1020
1049
  filters: [],
1021
1050
  type: :finally }),
1022
- have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1051
+ have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
1023
1052
  env: an_instance_of(Hash) }),
1024
1053
  have_attributes(name: 'format_response.grape', payload: { env: an_instance_of(Hash),
1025
1054
  formatter: a_kind_of(Module) })
@@ -1027,25 +1056,25 @@ describe Grape::Endpoint do
1027
1056
 
1028
1057
  # In order that events were initialized
1029
1058
  expect(@events.sort_by(&:time)).to contain_exactly(
1030
- have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1059
+ have_attributes(name: 'endpoint_run.grape', payload: { endpoint: a_kind_of(described_class),
1031
1060
  env: an_instance_of(Hash) }),
1032
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1061
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1033
1062
  filters: a_collection_containing_exactly(an_instance_of(Proc)),
1034
1063
  type: :before }),
1035
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1064
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1036
1065
  filters: [],
1037
1066
  type: :before_validation }),
1038
- have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1067
+ have_attributes(name: 'endpoint_run_validators.grape', payload: { endpoint: a_kind_of(described_class),
1039
1068
  validators: [],
1040
1069
  request: a_kind_of(Grape::Request) }),
1041
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1070
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1042
1071
  filters: [],
1043
1072
  type: :after_validation }),
1044
- have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(Grape::Endpoint) }),
1045
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1073
+ have_attributes(name: 'endpoint_render.grape', payload: { endpoint: a_kind_of(described_class) }),
1074
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1046
1075
  filters: [],
1047
1076
  type: :after }),
1048
- have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(Grape::Endpoint),
1077
+ have_attributes(name: 'endpoint_run_filters.grape', payload: { endpoint: a_kind_of(described_class),
1049
1078
  filters: [],
1050
1079
  type: :finally }),
1051
1080
  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