grape 1.1.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (306) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +370 -44
  3. data/CONTRIBUTING.md +32 -1
  4. data/LICENSE +1 -1
  5. data/README.md +683 -87
  6. data/UPGRADING.md +481 -17
  7. data/grape.gemspec +15 -4
  8. data/lib/grape/api/helpers.rb +2 -0
  9. data/lib/grape/api/instance.rb +279 -0
  10. data/lib/grape/api.rb +144 -176
  11. data/lib/grape/config.rb +34 -0
  12. data/lib/grape/content_types.rb +34 -0
  13. data/lib/grape/cookies.rb +4 -0
  14. data/lib/grape/dry_types.rb +12 -0
  15. data/lib/grape/dsl/api.rb +1 -1
  16. data/lib/grape/dsl/callbacks.rb +21 -1
  17. data/lib/grape/dsl/configuration.rb +1 -1
  18. data/lib/grape/dsl/desc.rb +41 -23
  19. data/lib/grape/dsl/headers.rb +7 -2
  20. data/lib/grape/dsl/helpers.rb +10 -7
  21. data/lib/grape/dsl/inside_route.rb +118 -62
  22. data/lib/grape/dsl/logger.rb +2 -0
  23. data/lib/grape/dsl/middleware.rb +11 -4
  24. data/lib/grape/dsl/parameters.rb +33 -19
  25. data/lib/grape/dsl/request_response.rb +12 -9
  26. data/lib/grape/dsl/routing.rb +22 -13
  27. data/lib/grape/dsl/settings.rb +10 -6
  28. data/lib/grape/dsl/validations.rb +19 -14
  29. data/lib/grape/eager_load.rb +20 -0
  30. data/lib/grape/endpoint.rb +67 -58
  31. data/lib/grape/error_formatter/base.rb +2 -0
  32. data/lib/grape/error_formatter/json.rb +11 -7
  33. data/lib/grape/error_formatter/txt.rb +2 -0
  34. data/lib/grape/error_formatter/xml.rb +4 -6
  35. data/lib/grape/error_formatter.rb +4 -2
  36. data/lib/grape/exceptions/base.rb +23 -16
  37. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  38. data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
  39. data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
  40. data/lib/grape/exceptions/invalid_formatter.rb +2 -0
  41. data/lib/grape/exceptions/invalid_message_body.rb +2 -0
  42. data/lib/grape/exceptions/invalid_response.rb +11 -0
  43. data/lib/grape/exceptions/invalid_version_header.rb +2 -0
  44. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
  45. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
  46. data/lib/grape/exceptions/method_not_allowed.rb +2 -0
  47. data/lib/grape/exceptions/missing_group_type.rb +10 -1
  48. data/lib/grape/exceptions/missing_mime_type.rb +2 -0
  49. data/lib/grape/exceptions/missing_option.rb +2 -0
  50. data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
  51. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  52. data/lib/grape/exceptions/unknown_options.rb +2 -0
  53. data/lib/grape/exceptions/unknown_parameter.rb +2 -0
  54. data/lib/grape/exceptions/unknown_validator.rb +2 -0
  55. data/lib/grape/exceptions/unsupported_group_type.rb +10 -1
  56. data/lib/grape/exceptions/validation.rb +5 -8
  57. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  58. data/lib/grape/exceptions/validation_errors.rb +16 -13
  59. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  60. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  61. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  62. data/lib/grape/extensions/hash.rb +2 -0
  63. data/lib/grape/extensions/hashie/mash.rb +2 -0
  64. data/lib/grape/formatter/json.rb +3 -0
  65. data/lib/grape/formatter/serializable_hash.rb +4 -1
  66. data/lib/grape/formatter/txt.rb +2 -0
  67. data/lib/grape/formatter/xml.rb +3 -0
  68. data/lib/grape/formatter.rb +5 -3
  69. data/lib/grape/http/headers.rb +50 -18
  70. data/lib/grape/locale/en.yml +11 -8
  71. data/lib/grape/middleware/auth/base.rb +7 -7
  72. data/lib/grape/middleware/auth/dsl.rb +9 -2
  73. data/lib/grape/middleware/auth/strategies.rb +2 -0
  74. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  75. data/lib/grape/middleware/base.rb +13 -8
  76. data/lib/grape/middleware/error.rb +22 -17
  77. data/lib/grape/middleware/filter.rb +2 -0
  78. data/lib/grape/middleware/formatter.rb +12 -10
  79. data/lib/grape/middleware/globals.rb +2 -0
  80. data/lib/grape/middleware/helpers.rb +12 -0
  81. data/lib/grape/middleware/stack.rb +16 -6
  82. data/lib/grape/middleware/versioner/accept_version_header.rb +5 -5
  83. data/lib/grape/middleware/versioner/header.rb +13 -9
  84. data/lib/grape/middleware/versioner/param.rb +4 -1
  85. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +5 -1
  86. data/lib/grape/middleware/versioner/path.rb +5 -1
  87. data/lib/grape/middleware/versioner.rb +2 -0
  88. data/lib/grape/namespace.rb +14 -2
  89. data/lib/grape/parser/json.rb +3 -1
  90. data/lib/grape/parser/xml.rb +3 -1
  91. data/lib/grape/parser.rb +4 -2
  92. data/lib/grape/path.rb +16 -3
  93. data/lib/grape/presenters/presenter.rb +2 -0
  94. data/lib/grape/request.rb +21 -9
  95. data/lib/grape/router/attribute_translator.rb +41 -8
  96. data/lib/grape/router/pattern.rb +21 -17
  97. data/lib/grape/router/route.rb +15 -29
  98. data/lib/grape/router.rb +36 -29
  99. data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
  100. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
  101. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
  102. data/lib/grape/types/invalid_value.rb +8 -0
  103. data/lib/grape/util/base_inheritable.rb +43 -0
  104. data/lib/grape/util/cache.rb +20 -0
  105. data/lib/grape/util/endpoint_configuration.rb +8 -0
  106. data/lib/grape/util/env.rb +19 -17
  107. data/lib/grape/util/inheritable_setting.rb +3 -3
  108. data/lib/grape/util/inheritable_values.rb +7 -25
  109. data/lib/grape/util/json.rb +4 -0
  110. data/lib/grape/util/lazy_block.rb +27 -0
  111. data/lib/grape/util/lazy_object.rb +43 -0
  112. data/lib/grape/util/lazy_value.rb +99 -0
  113. data/lib/grape/util/registrable.rb +2 -0
  114. data/lib/grape/util/reverse_stackable_values.rb +10 -35
  115. data/lib/grape/util/stackable_values.rb +21 -34
  116. data/lib/grape/util/strict_hash_configuration.rb +3 -1
  117. data/lib/grape/util/xml.rb +2 -0
  118. data/lib/grape/validations/attributes_doc.rb +58 -0
  119. data/lib/grape/validations/attributes_iterator.rb +16 -6
  120. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  121. data/lib/grape/validations/params_scope.rb +174 -94
  122. data/lib/grape/validations/single_attribute_iterator.rb +24 -0
  123. data/lib/grape/validations/types/array_coercer.rb +63 -0
  124. data/lib/grape/validations/types/build_coercer.rb +47 -49
  125. data/lib/grape/validations/types/custom_type_coercer.rb +30 -51
  126. data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
  127. data/lib/grape/validations/types/dry_type_coercer.rb +72 -0
  128. data/lib/grape/validations/types/file.rb +22 -18
  129. data/lib/grape/validations/types/invalid_value.rb +17 -0
  130. data/lib/grape/validations/types/json.rb +47 -39
  131. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  132. data/lib/grape/validations/types/primitive_coercer.rb +75 -0
  133. data/lib/grape/validations/types/set_coercer.rb +38 -0
  134. data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
  135. data/lib/grape/validations/types.rb +106 -63
  136. data/lib/grape/validations/validator_factory.rb +8 -11
  137. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  138. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  139. data/lib/grape/validations/validators/as_validator.rb +14 -0
  140. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  141. data/lib/grape/validations/validators/base.rb +84 -68
  142. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  143. data/lib/grape/validations/validators/default_validator.rb +51 -0
  144. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  145. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  146. data/lib/grape/validations/validators/multiple_params_base.rb +27 -16
  147. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  148. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  149. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  150. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  151. data/lib/grape/validations/validators/values_validator.rb +88 -0
  152. data/lib/grape/validations.rb +18 -6
  153. data/lib/grape/version.rb +3 -1
  154. data/lib/grape.rb +175 -94
  155. data/spec/grape/api/custom_validations_spec.rb +117 -44
  156. data/spec/grape/api/deeply_included_options_spec.rb +4 -4
  157. data/spec/grape/api/defines_boolean_in_params_spec.rb +38 -0
  158. data/spec/grape/api/documentation_spec.rb +59 -0
  159. data/spec/grape/api/inherited_helpers_spec.rb +1 -1
  160. data/spec/grape/api/instance_spec.rb +103 -0
  161. data/spec/grape/api/invalid_format_spec.rb +3 -1
  162. data/spec/grape/api/namespace_parameters_in_route_spec.rb +1 -1
  163. data/spec/grape/api/nested_helpers_spec.rb +1 -1
  164. data/spec/grape/api/optional_parameters_in_route_spec.rb +1 -1
  165. data/spec/grape/api/parameters_modification_spec.rb +2 -2
  166. data/spec/grape/api/patch_method_helpers_spec.rb +1 -1
  167. data/spec/grape/api/recognize_path_spec.rb +2 -2
  168. data/spec/grape/api/required_parameters_in_route_spec.rb +1 -1
  169. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +1 -1
  170. data/spec/grape/api/routes_with_requirements_spec.rb +59 -0
  171. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +10 -16
  172. data/spec/grape/api/shared_helpers_spec.rb +1 -1
  173. data/spec/grape/api_remount_spec.rb +473 -0
  174. data/spec/grape/api_spec.rb +995 -231
  175. data/spec/grape/config_spec.rb +17 -0
  176. data/spec/grape/dsl/callbacks_spec.rb +3 -2
  177. data/spec/grape/dsl/desc_spec.rb +43 -17
  178. data/spec/grape/dsl/headers_spec.rb +40 -10
  179. data/spec/grape/dsl/helpers_spec.rb +6 -5
  180. data/spec/grape/dsl/inside_route_spec.rb +189 -38
  181. data/spec/grape/dsl/logger_spec.rb +17 -19
  182. data/spec/grape/dsl/middleware_spec.rb +11 -2
  183. data/spec/grape/dsl/parameters_spec.rb +3 -1
  184. data/spec/grape/dsl/request_response_spec.rb +8 -7
  185. data/spec/grape/dsl/routing_spec.rb +22 -9
  186. data/spec/grape/dsl/settings_spec.rb +1 -1
  187. data/spec/grape/dsl/validations_spec.rb +1 -16
  188. data/spec/grape/endpoint/declared_spec.rb +846 -0
  189. data/spec/grape/endpoint_spec.rb +136 -577
  190. data/spec/grape/entity_spec.rb +31 -24
  191. data/spec/grape/exceptions/base_spec.rb +81 -0
  192. data/spec/grape/exceptions/body_parse_errors_spec.rb +4 -1
  193. data/spec/grape/exceptions/invalid_accept_header_spec.rb +65 -23
  194. data/spec/grape/exceptions/invalid_formatter_spec.rb +1 -1
  195. data/spec/grape/exceptions/invalid_response_spec.rb +11 -0
  196. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -2
  197. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  198. data/spec/grape/exceptions/missing_mime_type_spec.rb +1 -1
  199. data/spec/grape/exceptions/missing_option_spec.rb +2 -2
  200. data/spec/grape/exceptions/unknown_options_spec.rb +1 -1
  201. data/spec/grape/exceptions/unknown_validator_spec.rb +1 -1
  202. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  203. data/spec/grape/exceptions/validation_errors_spec.rb +21 -15
  204. data/spec/grape/exceptions/validation_spec.rb +6 -4
  205. data/spec/grape/extensions/param_builders/hash_spec.rb +8 -8
  206. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +9 -9
  207. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +9 -9
  208. data/spec/grape/integration/global_namespace_function_spec.rb +2 -2
  209. data/spec/grape/integration/rack_sendfile_spec.rb +14 -10
  210. data/spec/grape/integration/rack_spec.rb +25 -8
  211. data/spec/grape/loading_spec.rb +9 -9
  212. data/spec/grape/middleware/auth/base_spec.rb +2 -1
  213. data/spec/grape/middleware/auth/dsl_spec.rb +19 -10
  214. data/spec/grape/middleware/auth/strategies_spec.rb +62 -22
  215. data/spec/grape/middleware/base_spec.rb +36 -17
  216. data/spec/grape/middleware/error_spec.rb +11 -4
  217. data/spec/grape/middleware/exception_spec.rb +112 -162
  218. data/spec/grape/middleware/formatter_spec.rb +65 -29
  219. data/spec/grape/middleware/globals_spec.rb +8 -5
  220. data/spec/grape/middleware/stack_spec.rb +25 -13
  221. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -2
  222. data/spec/grape/middleware/versioner/header_spec.rb +37 -14
  223. data/spec/grape/middleware/versioner/param_spec.rb +8 -2
  224. data/spec/grape/middleware/versioner/path_spec.rb +6 -2
  225. data/spec/grape/middleware/versioner_spec.rb +2 -2
  226. data/spec/grape/named_api_spec.rb +19 -0
  227. data/spec/grape/parser_spec.rb +10 -6
  228. data/spec/grape/path_spec.rb +53 -53
  229. data/spec/grape/presenters/presenter_spec.rb +8 -7
  230. data/spec/grape/request_spec.rb +29 -3
  231. data/spec/grape/util/inheritable_setting_spec.rb +9 -8
  232. data/spec/grape/util/inheritable_values_spec.rb +5 -3
  233. data/spec/grape/util/reverse_stackable_values_spec.rb +5 -2
  234. data/spec/grape/util/stackable_values_spec.rb +10 -7
  235. data/spec/grape/util/strict_hash_configuration_spec.rb +2 -1
  236. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  237. data/spec/grape/validations/instance_behaivour_spec.rb +13 -14
  238. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +40 -0
  239. data/spec/grape/validations/params_scope_spec.rb +568 -99
  240. data/spec/grape/validations/single_attribute_iterator_spec.rb +57 -0
  241. data/spec/grape/validations/types/array_coercer_spec.rb +33 -0
  242. data/spec/grape/validations/types/primitive_coercer_spec.rb +150 -0
  243. data/spec/grape/validations/types/set_coercer_spec.rb +32 -0
  244. data/spec/grape/validations/types_spec.rb +44 -45
  245. data/spec/grape/validations/validators/all_or_none_spec.rb +134 -32
  246. data/spec/grape/validations/validators/allow_blank_spec.rb +137 -141
  247. data/spec/grape/validations/validators/at_least_one_of_spec.rb +169 -31
  248. data/spec/grape/validations/validators/coerce_spec.rb +491 -151
  249. data/spec/grape/validations/validators/default_spec.rb +242 -78
  250. data/spec/grape/validations/validators/exactly_one_of_spec.rb +198 -40
  251. data/spec/grape/validations/validators/except_values_spec.rb +6 -5
  252. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +181 -30
  253. data/spec/grape/validations/validators/presence_spec.rb +45 -2
  254. data/spec/grape/validations/validators/regexp_spec.rb +27 -33
  255. data/spec/grape/validations/validators/same_as_spec.rb +57 -0
  256. data/spec/grape/validations/validators/values_spec.rb +227 -180
  257. data/spec/grape/validations_spec.rb +502 -72
  258. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  259. data/spec/integration/multi_json/json_spec.rb +2 -2
  260. data/spec/integration/multi_xml/xml_spec.rb +2 -2
  261. data/spec/shared/versioning_examples.rb +34 -29
  262. data/spec/spec_helper.rb +31 -5
  263. data/spec/support/basic_auth_encode_helpers.rb +3 -1
  264. data/spec/support/chunks.rb +14 -0
  265. data/spec/support/content_type_helpers.rb +2 -0
  266. data/spec/support/endpoint_faker.rb +2 -0
  267. data/spec/support/file_streamer.rb +2 -0
  268. data/spec/support/integer_helpers.rb +2 -0
  269. data/spec/support/versioned_helpers.rb +8 -8
  270. metadata +111 -61
  271. data/Appraisals +0 -32
  272. data/Dangerfile +0 -2
  273. data/Gemfile +0 -33
  274. data/Gemfile.lock +0 -231
  275. data/Guardfile +0 -10
  276. data/RELEASING.md +0 -111
  277. data/Rakefile +0 -25
  278. data/benchmark/simple.rb +0 -27
  279. data/benchmark/simple_with_type_coercer.rb +0 -22
  280. data/gemfiles/multi_json.gemfile +0 -35
  281. data/gemfiles/multi_xml.gemfile +0 -35
  282. data/gemfiles/rack_1.5.2.gemfile +0 -35
  283. data/gemfiles/rack_edge.gemfile +0 -35
  284. data/gemfiles/rails_3.gemfile +0 -36
  285. data/gemfiles/rails_4.gemfile +0 -35
  286. data/gemfiles/rails_5.gemfile +0 -35
  287. data/gemfiles/rails_edge.gemfile +0 -35
  288. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  289. data/lib/grape/util/content_types.rb +0 -26
  290. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
  291. data/lib/grape/validations/validators/all_or_none.rb +0 -20
  292. data/lib/grape/validations/validators/allow_blank.rb +0 -16
  293. data/lib/grape/validations/validators/as.rb +0 -15
  294. data/lib/grape/validations/validators/at_least_one_of.rb +0 -20
  295. data/lib/grape/validations/validators/coerce.rb +0 -74
  296. data/lib/grape/validations/validators/default.rb +0 -48
  297. data/lib/grape/validations/validators/exactly_one_of.rb +0 -29
  298. data/lib/grape/validations/validators/except_values.rb +0 -20
  299. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -25
  300. data/lib/grape/validations/validators/presence.rb +0 -10
  301. data/lib/grape/validations/validators/regexp.rb +0 -11
  302. data/lib/grape/validations/validators/values.rb +0 -71
  303. data/pkg/grape-0.17.0.gem +0 -0
  304. data/pkg/grape-0.19.0.gem +0 -0
  305. data/spec/grape/dsl/configuration_spec.rb +0 -14
  306. data/spec/grape/validations/attributes_iterator_spec.rb +0 -4
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::Exceptions::UnknownValidator do
4
4
  describe '#message' do
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Grape::Exceptions::UnsupportedGroupType do
4
+ subject { described_class.new }
5
+
6
+ describe '#message' do
7
+ subject { described_class.new.message }
8
+
9
+ it { is_expected.to include 'group type must be Array, Hash, JSON or Array[JSON]' }
10
+ end
11
+
12
+ describe 'deprecated Grape::Exceptions::UnsupportedGroupTypeError' do
13
+ subject { Grape::Exceptions::UnsupportedGroupTypeError.new }
14
+
15
+ it 'puts a deprecation warning' do
16
+ expect(Warning).to receive(:warn) do |message|
17
+ expect(message).to include('`Grape::Exceptions::UnsupportedGroupTypeError` is deprecated')
18
+ end
19
+
20
+ subject
21
+ end
22
+ end
23
+ end
@@ -1,32 +1,34 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'ostruct'
3
4
 
4
5
  describe Grape::Exceptions::ValidationErrors do
5
6
  let(:validation_message) { 'FooBar is invalid' }
6
- let(:validation_error) { OpenStruct.new(params: [validation_message]) }
7
+ let(:validation_error) { instance_double Grape::Exceptions::Validation, params: [validation_message], message: '' }
7
8
 
8
9
  context 'initialize' do
10
+ subject do
11
+ described_class.new(errors: [validation_error], headers: headers)
12
+ end
13
+
9
14
  let(:headers) do
10
15
  {
11
16
  'A-Header-Key' => 'A-Header-Value'
12
17
  }
13
18
  end
14
19
 
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
+ it 'assigns headers through base class' do
20
21
  expect(subject.headers).to eq(headers)
21
22
  end
22
23
  end
23
24
 
24
25
  context 'message' do
25
26
  context 'is not repeated' do
27
+ subject(:message) { error.message.split(',').map(&:strip) }
28
+
26
29
  let(:error) do
27
30
  described_class.new(errors: [validation_error, validation_error])
28
31
  end
29
- subject(:message) { error.message.split(',').map(&:strip) }
30
32
 
31
33
  it { expect(message).to include validation_message }
32
34
  it { expect(message.size).to eq 1 }
@@ -35,9 +37,10 @@ describe Grape::Exceptions::ValidationErrors do
35
37
 
36
38
  describe '#full_messages' do
37
39
  context 'with errors' do
40
+ subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
41
+
38
42
  let(:validation_error_1) { Grape::Exceptions::Validation.new(params: ['id'], message: :presence) }
39
43
  let(:validation_error_2) { Grape::Exceptions::Validation.new(params: ['name'], message: :presence) }
40
- subject { described_class.new(errors: [validation_error_1, validation_error_2]).full_messages }
41
44
 
42
45
  it 'returns an array with each errors full message' do
43
46
  expect(subject).to contain_exactly('id is missing', 'name is missing')
@@ -45,9 +48,10 @@ describe Grape::Exceptions::ValidationErrors do
45
48
  end
46
49
 
47
50
  context 'when attributes is an array of symbols' do
48
- let(:validation_error) { Grape::Exceptions::Validation.new(params: [:admin_field], message: 'Can not set admin-only field') }
49
51
  subject { described_class.new(errors: [validation_error]).full_messages }
50
52
 
53
+ let(:validation_error) { Grape::Exceptions::Validation.new(params: [:admin_field], message: 'Can not set admin-only field') }
54
+
51
55
  it 'returns an array with an error full message' do
52
56
  expect(subject.first).to eq('admin_field Can not set admin-only field')
53
57
  end
@@ -63,7 +67,7 @@ describe Grape::Exceptions::ValidationErrors do
63
67
 
64
68
  it 'can return structured json with separate fields' do
65
69
  subject.format :json
66
- subject.rescue_from Grape::Exceptions::ValidationErrors do |e|
70
+ subject.rescue_from described_class do |e|
67
71
  error!(e, 400)
68
72
  end
69
73
  subject.params do
@@ -77,10 +81,12 @@ describe Grape::Exceptions::ValidationErrors do
77
81
  end
78
82
  get '/exactly_one_of', beer: 'string', wine: 'anotherstring'
79
83
  expect(last_response.status).to eq(400)
80
- expect(JSON.parse(last_response.body)).to eq([
81
- 'params' => %w[beer wine],
82
- 'messages' => ['are mutually exclusive']
83
- ])
84
+ expect(JSON.parse(last_response.body)).to eq(
85
+ [
86
+ 'params' => %w[beer wine],
87
+ 'messages' => ['are mutually exclusive']
88
+ ]
89
+ )
84
90
  end
85
91
  end
86
92
  end
@@ -1,17 +1,19 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::Exceptions::Validation do
4
4
  it 'fails when params are missing' do
5
- expect { Grape::Exceptions::Validation.new(message: 'presence') }.to raise_error(ArgumentError, 'missing keyword: params')
5
+ expect { described_class.new(message: 'presence') }.to raise_error(ArgumentError, /missing keyword:.+?params/)
6
6
  end
7
+
7
8
  context 'when message is a symbol' do
8
9
  it 'stores message_key' do
9
- expect(Grape::Exceptions::Validation.new(params: ['id'], message: :presence).message_key).to eq(:presence)
10
+ expect(described_class.new(params: ['id'], message: :presence).message_key).to eq(:presence)
10
11
  end
11
12
  end
13
+
12
14
  context 'when message is a String' do
13
15
  it 'does not store the message_key' do
14
- expect(Grape::Exceptions::Validation.new(params: ['id'], message: 'presence').message_key).to eq(nil)
16
+ expect(described_class.new(params: ['id'], message: 'presence').message_key).to be_nil
15
17
  end
16
18
  end
17
19
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::Extensions::Hash::ParamBuilder do
4
4
  subject { Class.new(Grape::API) }
@@ -8,10 +8,10 @@ describe Grape::Extensions::Hash::ParamBuilder do
8
8
  end
9
9
 
10
10
  describe 'in an endpoint' do
11
- context '#params' do
11
+ describe '#params' do
12
12
  before do
13
13
  subject.params do
14
- build_with Grape::Extensions::Hash::ParamBuilder
14
+ build_with Grape::Extensions::Hash::ParamBuilder # rubocop:disable RSpec/DescribedClass
15
15
  end
16
16
 
17
17
  subject.get do
@@ -19,7 +19,7 @@ describe Grape::Extensions::Hash::ParamBuilder do
19
19
  end
20
20
  end
21
21
 
22
- it 'should be of type Hash' do
22
+ it 'is of type Hash' do
23
23
  get '/'
24
24
  expect(last_response.status).to eq(200)
25
25
  expect(last_response.body).to eq('Hash')
@@ -29,17 +29,17 @@ describe Grape::Extensions::Hash::ParamBuilder do
29
29
 
30
30
  describe 'in an api' do
31
31
  before do
32
- subject.send(:include, Grape::Extensions::Hash::ParamBuilder)
32
+ subject.send(:include, Grape::Extensions::Hash::ParamBuilder) # rubocop:disable RSpec/DescribedClass
33
33
  end
34
34
 
35
- context '#params' do
35
+ describe '#params' do
36
36
  before do
37
37
  subject.get do
38
38
  params.class
39
39
  end
40
40
  end
41
41
 
42
- it 'should be Hash' do
42
+ it 'is Hash' do
43
43
  get '/'
44
44
  expect(last_response.status).to eq(200)
45
45
  expect(last_response.body).to eq('Hash')
@@ -67,7 +67,7 @@ describe Grape::Extensions::Hash::ParamBuilder do
67
67
 
68
68
  it 'symbolizes the params' do
69
69
  subject.params do
70
- build_with Grape::Extensions::Hash::ParamBuilder
70
+ build_with Grape::Extensions::Hash::ParamBuilder # rubocop:disable RSpec/DescribedClass
71
71
  requires :a, type: String
72
72
  end
73
73
 
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder do
4
4
  subject { Class.new(Grape::API) }
@@ -8,10 +8,10 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
8
8
  end
9
9
 
10
10
  describe 'in an endpoint' do
11
- context '#params' do
11
+ describe '#params' do
12
12
  before do
13
13
  subject.params do
14
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
14
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
15
15
  end
16
16
 
17
17
  subject.get do
@@ -19,7 +19,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
19
19
  end
20
20
  end
21
21
 
22
- it 'should be of type Hash' do
22
+ it 'is of type Hash' do
23
23
  get '/'
24
24
  expect(last_response.status).to eq(200)
25
25
  expect(last_response.body).to eq('ActiveSupport::HashWithIndifferentAccess')
@@ -29,10 +29,10 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
29
29
 
30
30
  describe 'in an api' do
31
31
  before do
32
- subject.send(:include, Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder)
32
+ subject.send(:include, Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder) # rubocop:disable RSpec/DescribedClass
33
33
  end
34
34
 
35
- context '#params' do
35
+ describe '#params' do
36
36
  before do
37
37
  subject.get do
38
38
  params.class
@@ -47,7 +47,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
47
47
 
48
48
  it 'parses sub hash params' do
49
49
  subject.params do
50
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
50
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
51
51
 
52
52
  optional :a, type: Hash do
53
53
  optional :b, type: Hash do
@@ -68,7 +68,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
68
68
 
69
69
  it 'params are indifferent to symbol or string keys' do
70
70
  subject.params do
71
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
71
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
72
72
  optional :a, type: Hash do
73
73
  optional :b, type: Hash do
74
74
  optional :c, type: String
@@ -88,7 +88,7 @@ describe Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuild
88
88
 
89
89
  it 'responds to string keys' do
90
90
  subject.params do
91
- build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
91
+ build_with Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder # rubocop:disable RSpec/DescribedClass
92
92
  requires :a, type: String
93
93
  end
94
94
 
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::Extensions::Hashie::Mash::ParamBuilder do
4
4
  subject { Class.new(Grape::API) }
@@ -8,10 +8,10 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
8
8
  end
9
9
 
10
10
  describe 'in an endpoint' do
11
- context '#params' do
11
+ describe '#params' do
12
12
  before do
13
13
  subject.params do
14
- build_with Grape::Extensions::Hashie::Mash::ParamBuilder
14
+ build_with Grape::Extensions::Hashie::Mash::ParamBuilder # rubocop:disable RSpec/DescribedClass
15
15
  end
16
16
 
17
17
  subject.get do
@@ -19,7 +19,7 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
19
19
  end
20
20
  end
21
21
 
22
- it 'should be of type Hashie::Mash' do
22
+ it 'is of type Hashie::Mash' do
23
23
  get '/'
24
24
  expect(last_response.status).to eq(200)
25
25
  expect(last_response.body).to eq('Hashie::Mash')
@@ -29,17 +29,17 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
29
29
 
30
30
  describe 'in an api' do
31
31
  before do
32
- subject.send(:include, Grape::Extensions::Hashie::Mash::ParamBuilder)
32
+ subject.send(:include, Grape::Extensions::Hashie::Mash::ParamBuilder) # rubocop:disable RSpec/DescribedClass
33
33
  end
34
34
 
35
- context '#params' do
35
+ describe '#params' do
36
36
  before do
37
37
  subject.get do
38
38
  params.class
39
39
  end
40
40
  end
41
41
 
42
- it 'should be Hashie::Mash' do
42
+ it 'is Hashie::Mash' do
43
43
  get '/'
44
44
  expect(last_response.status).to eq(200)
45
45
  expect(last_response.body).to eq('Hashie::Mash')
@@ -55,7 +55,7 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
55
55
  end
56
56
  end
57
57
 
58
- it 'should be Hashie::Mash' do
58
+ it 'is Hashie::Mash' do
59
59
  get '/foo'
60
60
  expect(last_response.status).to eq(200)
61
61
  expect(last_response.body).to eq('Hashie::Mash')
@@ -64,7 +64,7 @@ describe Grape::Extensions::Hashie::Mash::ParamBuilder do
64
64
 
65
65
  it 'is indifferent to key or symbol access' do
66
66
  subject.params do
67
- build_with Grape::Extensions::Hashie::Mash::ParamBuilder
67
+ build_with Grape::Extensions::Hashie::Mash::ParamBuilder # rubocop:disable RSpec/DescribedClass
68
68
  requires :a, type: String
69
69
  end
70
70
  subject.get '/foo' do
@@ -1,6 +1,6 @@
1
- # see https://github.com/ruby-grape/grape/issues/1348
1
+ # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ # see https://github.com/ruby-grape/grape/issues/1348
4
4
 
5
5
  def namespace
6
6
  raise
@@ -1,13 +1,17 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Rack::Sendfile do
4
4
  subject do
5
- send_file = file_streamer
5
+ content_object = file_object
6
6
  app = Class.new(Grape::API) do
7
7
  use Rack::Sendfile
8
8
  format :json
9
9
  get do
10
- file send_file
10
+ if content_object.is_a?(String)
11
+ sendfile content_object
12
+ else
13
+ stream content_object
14
+ end
11
15
  end
12
16
  end
13
17
 
@@ -20,9 +24,9 @@ describe Rack::Sendfile do
20
24
  app.call(env)
21
25
  end
22
26
 
23
- context do
24
- let(:file_streamer) do
25
- double(:file_streamer, to_path: '/accel/mapping/some/path')
27
+ context 'when calling sendfile' do
28
+ let(:file_object) do
29
+ '/accel/mapping/some/path'
26
30
  end
27
31
 
28
32
  it 'contains Sendfile headers' do
@@ -31,14 +35,14 @@ describe Rack::Sendfile do
31
35
  end
32
36
  end
33
37
 
34
- context do
35
- let(:file_streamer) do
36
- double(:file_streamer)
38
+ context 'when streaming non file content' do
39
+ let(:file_object) do
40
+ double(:file_object, each: nil)
37
41
  end
38
42
 
39
43
  it 'not contains Sendfile headers' do
40
44
  headers = subject[1]
41
- expect(headers).to_not include('X-Accel-Redirect')
45
+ expect(headers).not_to include('X-Accel-Redirect')
42
46
  end
43
47
  end
44
48
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Rack do
4
4
  it 'correctly populates params from a Tempfile' do
@@ -19,16 +19,33 @@ describe Rack do
19
19
  }
20
20
  env = Rack::MockRequest.env_for('/', options)
21
21
 
22
- unless RUBY_PLATFORM == 'java'
23
- major, minor, patch = Rack.release.split('.').map(&:to_i)
24
- patch ||= 0 # rack <= 1.5.2 does not specify patch version
25
- pending 'Rack 1.5.3 or 1.6.1 required' unless major >= 2 || (major >= 1 && ((minor == 5 && patch >= 3) || (minor >= 6)))
26
- end
27
-
28
- expect(JSON.parse(app.call(env)[2].body.first)['params_keys']).to match_array('test')
22
+ expect(JSON.parse(read_chunks(app.call(env)[2]).join)['params_keys']).to match_array('test')
29
23
  ensure
30
24
  input.close
31
25
  input.unlink
32
26
  end
33
27
  end
28
+
29
+ context 'when the app is mounted' do
30
+ let(:ping_mount) do
31
+ Class.new(Grape::API) do
32
+ get 'ping'
33
+ end
34
+ end
35
+
36
+ let(:app) do
37
+ app_to_mount = ping_mount
38
+ app = Class.new(Grape::API) do
39
+ namespace 'namespace' do
40
+ mount app_to_mount
41
+ end
42
+ end
43
+ Rack::Builder.new(app)
44
+ end
45
+
46
+ it 'finds the app on the namespace' do
47
+ get '/namespace/ping'
48
+ expect(last_response.status).to eq 200
49
+ end
50
+ end
34
51
  end
@@ -1,6 +1,14 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::API do
4
+ subject do
5
+ CombinedApi = combined_api
6
+ Class.new(Grape::API) do
7
+ format :json
8
+ mount CombinedApi => '/'
9
+ end
10
+ end
11
+
4
12
  let(:jobs_api) do
5
13
  Class.new(Grape::API) do
6
14
  namespace :one do
@@ -24,14 +32,6 @@ describe Grape::API do
24
32
  end
25
33
  end
26
34
 
27
- subject do
28
- CombinedApi = combined_api
29
- Class.new(Grape::API) do
30
- format :json
31
- mount CombinedApi => '/'
32
- end
33
- end
34
-
35
35
  def app
36
36
  subject
37
37
  end
@@ -1,4 +1,5 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'base64'
3
4
 
4
5
  describe Grape::Middleware::Auth::Base do
@@ -1,9 +1,9 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe Grape::Middleware::Auth::DSL do
4
4
  subject { Class.new(Grape::API) }
5
5
 
6
- let(:block) { ->() {} }
6
+ let(:block) { -> {} }
7
7
  let(:settings) do
8
8
  {
9
9
  opaque: 'secret',
@@ -14,16 +14,16 @@ describe Grape::Middleware::Auth::DSL do
14
14
  end
15
15
 
16
16
  describe '.auth' do
17
- it 'stets auth parameters' do
18
- expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
17
+ it 'sets auth parameters' do
18
+ expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
19
19
 
20
20
  subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
21
21
  expect(subject.auth).to eq(settings)
22
22
  end
23
23
 
24
24
  it 'can be called multiple times' do
25
- expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
26
- expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings.merge(realm: 'super_secret'))
25
+ expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
26
+ expect(subject.base_instance).to receive(:use).with(Grape::Middleware::Auth::Base, settings.merge(realm: 'super_secret'))
27
27
 
28
28
  subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
29
29
  first_settings = subject.auth
@@ -36,16 +36,25 @@ describe Grape::Middleware::Auth::DSL do
36
36
  end
37
37
 
38
38
  describe '.http_basic' do
39
- it 'stets auth parameters' do
39
+ it 'sets auth parameters' do
40
40
  subject.http_basic realm: 'my_realm', &settings[:proc]
41
41
  expect(subject.auth).to eq(realm: 'my_realm', type: :http_basic, proc: block)
42
42
  end
43
43
  end
44
44
 
45
45
  describe '.http_digest' do
46
- it 'stets auth parameters' do
47
- subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
48
- expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
46
+ context 'when realm is a hash' do
47
+ it 'sets auth parameters' do
48
+ subject.http_digest realm: { realm: 'my_realm', opaque: 'my_opaque' }, &settings[:proc]
49
+ expect(subject.auth).to eq(realm: { realm: 'my_realm', opaque: 'my_opaque' }, type: :http_digest, proc: block)
50
+ end
51
+ end
52
+
53
+ context 'when realm is not hash' do
54
+ it 'sets auth parameters' do
55
+ subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
56
+ expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
57
+ end
49
58
  end
50
59
  end
51
60
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'base64'
4
4
 
@@ -34,13 +34,23 @@ describe Grape::Middleware::Auth::Strategies do
34
34
  RSpec::Matchers.define :be_challenge do
35
35
  match do |actual_response|
36
36
  actual_response.status == 401 &&
37
- actual_response['WWW-Authenticate'] =~ /^Digest / &&
37
+ actual_response['WWW-Authenticate'].start_with?('Digest ') &&
38
38
  actual_response.body.empty?
39
39
  end
40
40
  end
41
41
 
42
42
  module StrategiesSpec
43
- class Test < Grape::API
43
+ class PasswordHashed < Grape::API
44
+ http_digest(realm: { realm: 'Test Api', opaque: 'secret', passwords_hashed: true }) do |username|
45
+ { 'foo' => Digest::MD5.hexdigest(['foo', 'Test Api', 'bar'].join(':')) }[username]
46
+ end
47
+
48
+ get '/test' do
49
+ [{ hey: 'you' }, { there: 'bar' }, { foo: 'baz' }]
50
+ end
51
+ end
52
+
53
+ class PasswordIsNotHashed < Grape::API
44
54
  http_digest(realm: 'Test Api', opaque: 'secret') do |username|
45
55
  { 'foo' => 'bar' }[username]
46
56
  end
@@ -51,30 +61,60 @@ describe Grape::Middleware::Auth::Strategies do
51
61
  end
52
62
  end
53
63
 
54
- def app
55
- StrategiesSpec::Test
56
- end
64
+ context 'when password is hashed' do
65
+ def app
66
+ StrategiesSpec::PasswordHashed
67
+ end
57
68
 
58
- it 'is a digest authentication challenge' do
59
- get '/test'
60
- expect(last_response).to be_challenge
61
- end
69
+ it 'is a digest authentication challenge' do
70
+ get '/test'
71
+ expect(last_response).to be_challenge
72
+ end
62
73
 
63
- it 'throws a 401 if no auth is given' do
64
- get '/test'
65
- expect(last_response.status).to eq(401)
66
- end
74
+ it 'throws a 401 if no auth is given' do
75
+ get '/test'
76
+ expect(last_response.status).to eq(401)
77
+ end
67
78
 
68
- it 'authenticates if given valid creds' do
69
- digest_authorize 'foo', 'bar'
70
- get '/test'
71
- expect(last_response.status).to eq(200)
79
+ it 'authenticates if given valid creds' do
80
+ digest_authorize 'foo', 'bar'
81
+ get '/test'
82
+ expect(last_response.status).to eq(200)
83
+ end
84
+
85
+ it 'throws a 401 if given invalid creds' do
86
+ digest_authorize 'bar', 'foo'
87
+ get '/test'
88
+ expect(last_response.status).to eq(401)
89
+ end
72
90
  end
73
91
 
74
- it 'throws a 401 if given invalid creds' do
75
- digest_authorize 'bar', 'foo'
76
- get '/test'
77
- expect(last_response.status).to eq(401)
92
+ context 'when password is not hashed' do
93
+ def app
94
+ StrategiesSpec::PasswordIsNotHashed
95
+ end
96
+
97
+ it 'is a digest authentication challenge' do
98
+ get '/test'
99
+ expect(last_response).to be_challenge
100
+ end
101
+
102
+ it 'throws a 401 if no auth is given' do
103
+ get '/test'
104
+ expect(last_response.status).to eq(401)
105
+ end
106
+
107
+ it 'authenticates if given valid creds' do
108
+ digest_authorize 'foo', 'bar'
109
+ get '/test'
110
+ expect(last_response.status).to eq(200)
111
+ end
112
+
113
+ it 'throws a 401 if given invalid creds' do
114
+ digest_authorize 'bar', 'foo'
115
+ get '/test'
116
+ expect(last_response.status).to eq(401)
117
+ end
78
118
  end
79
119
  end
80
120
  end