grape 1.0.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (284) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +346 -39
  3. data/LICENSE +1 -1
  4. data/README.md +658 -90
  5. data/UPGRADING.md +472 -17
  6. data/grape.gemspec +17 -6
  7. data/lib/grape/api/helpers.rb +2 -0
  8. data/lib/grape/api/instance.rb +279 -0
  9. data/lib/grape/api.rb +132 -176
  10. data/lib/grape/config.rb +34 -0
  11. data/lib/grape/content_types.rb +34 -0
  12. data/lib/grape/cookies.rb +4 -0
  13. data/lib/grape/dsl/api.rb +2 -0
  14. data/lib/grape/dsl/callbacks.rb +22 -0
  15. data/lib/grape/dsl/configuration.rb +2 -0
  16. data/lib/grape/dsl/desc.rb +44 -12
  17. data/lib/grape/dsl/headers.rb +2 -0
  18. data/lib/grape/dsl/helpers.rb +11 -6
  19. data/lib/grape/dsl/inside_route.rb +116 -36
  20. data/lib/grape/dsl/logger.rb +2 -0
  21. data/lib/grape/dsl/middleware.rb +12 -3
  22. data/lib/grape/dsl/parameters.rb +34 -16
  23. data/lib/grape/dsl/request_response.rb +13 -8
  24. data/lib/grape/dsl/routing.rb +19 -12
  25. data/lib/grape/dsl/settings.rb +22 -4
  26. data/lib/grape/dsl/validations.rb +24 -4
  27. data/lib/grape/eager_load.rb +20 -0
  28. data/lib/grape/endpoint.rb +66 -57
  29. data/lib/grape/error_formatter/base.rb +2 -0
  30. data/lib/grape/error_formatter/json.rb +6 -4
  31. data/lib/grape/error_formatter/txt.rb +10 -3
  32. data/lib/grape/error_formatter/xml.rb +6 -4
  33. data/lib/grape/error_formatter.rb +4 -2
  34. data/lib/grape/exceptions/base.rb +22 -14
  35. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  36. data/lib/grape/exceptions/incompatible_option_values.rb +2 -1
  37. data/lib/grape/exceptions/invalid_accept_header.rb +2 -1
  38. data/lib/grape/exceptions/invalid_formatter.rb +2 -1
  39. data/lib/grape/exceptions/invalid_message_body.rb +2 -1
  40. data/lib/grape/exceptions/invalid_response.rb +11 -0
  41. data/lib/grape/exceptions/invalid_version_header.rb +2 -1
  42. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -1
  43. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -1
  44. data/lib/grape/exceptions/method_not_allowed.rb +2 -1
  45. data/lib/grape/exceptions/missing_group_type.rb +2 -1
  46. data/lib/grape/exceptions/missing_mime_type.rb +2 -1
  47. data/lib/grape/exceptions/missing_option.rb +2 -1
  48. data/lib/grape/exceptions/missing_vendor_option.rb +2 -1
  49. data/lib/grape/exceptions/unknown_options.rb +2 -1
  50. data/lib/grape/exceptions/unknown_parameter.rb +2 -1
  51. data/lib/grape/exceptions/unknown_validator.rb +2 -1
  52. data/lib/grape/exceptions/unsupported_group_type.rb +2 -1
  53. data/lib/grape/exceptions/validation.rb +5 -4
  54. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  55. data/lib/grape/exceptions/validation_errors.rb +16 -13
  56. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  57. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  58. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  59. data/lib/grape/extensions/hash.rb +2 -0
  60. data/lib/grape/extensions/hashie/mash.rb +2 -0
  61. data/lib/grape/formatter/json.rb +3 -0
  62. data/lib/grape/formatter/serializable_hash.rb +4 -1
  63. data/lib/grape/formatter/txt.rb +2 -0
  64. data/lib/grape/formatter/xml.rb +3 -0
  65. data/lib/grape/formatter.rb +5 -3
  66. data/lib/grape/http/headers.rb +50 -18
  67. data/lib/grape/locale/en.yml +3 -1
  68. data/lib/grape/middleware/auth/base.rb +7 -7
  69. data/lib/grape/middleware/auth/dsl.rb +2 -0
  70. data/lib/grape/middleware/auth/strategies.rb +2 -0
  71. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  72. data/lib/grape/middleware/base.rb +12 -7
  73. data/lib/grape/middleware/error.rb +75 -61
  74. data/lib/grape/middleware/filter.rb +2 -0
  75. data/lib/grape/middleware/formatter.rb +17 -13
  76. data/lib/grape/middleware/globals.rb +2 -0
  77. data/lib/grape/middleware/helpers.rb +12 -0
  78. data/lib/grape/middleware/stack.rb +15 -5
  79. data/lib/grape/middleware/versioner/accept_version_header.rb +5 -5
  80. data/lib/grape/middleware/versioner/header.rb +13 -9
  81. data/lib/grape/middleware/versioner/param.rb +4 -1
  82. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +5 -1
  83. data/lib/grape/middleware/versioner/path.rb +5 -1
  84. data/lib/grape/middleware/versioner.rb +2 -0
  85. data/lib/grape/namespace.rb +15 -3
  86. data/lib/grape/parser/json.rb +3 -1
  87. data/lib/grape/parser/xml.rb +3 -1
  88. data/lib/grape/parser.rb +4 -2
  89. data/lib/grape/path.rb +16 -3
  90. data/lib/grape/presenters/presenter.rb +2 -0
  91. data/lib/grape/request.rb +19 -9
  92. data/lib/grape/router/attribute_translator.rb +41 -8
  93. data/lib/grape/router/pattern.rb +22 -18
  94. data/lib/grape/router/route.rb +16 -30
  95. data/lib/grape/router.rb +37 -28
  96. data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
  97. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
  98. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
  99. data/lib/grape/util/base_inheritable.rb +43 -0
  100. data/lib/grape/util/cache.rb +20 -0
  101. data/lib/grape/util/endpoint_configuration.rb +8 -0
  102. data/lib/grape/util/env.rb +19 -17
  103. data/lib/grape/util/inheritable_setting.rb +3 -3
  104. data/lib/grape/util/inheritable_values.rb +7 -25
  105. data/lib/grape/util/json.rb +2 -0
  106. data/lib/grape/util/lazy_block.rb +27 -0
  107. data/lib/grape/util/lazy_object.rb +43 -0
  108. data/lib/grape/util/lazy_value.rb +99 -0
  109. data/lib/grape/util/registrable.rb +2 -0
  110. data/lib/grape/util/reverse_stackable_values.rb +10 -35
  111. data/lib/grape/util/stackable_values.rb +21 -34
  112. data/lib/grape/util/strict_hash_configuration.rb +2 -0
  113. data/lib/grape/util/xml.rb +2 -0
  114. data/lib/grape/validations/attributes_iterator.rb +16 -6
  115. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  116. data/lib/grape/validations/params_scope.rb +128 -66
  117. data/lib/grape/validations/single_attribute_iterator.rb +24 -0
  118. data/lib/grape/validations/types/array_coercer.rb +65 -0
  119. data/lib/grape/validations/types/build_coercer.rb +52 -46
  120. data/lib/grape/validations/types/custom_type_coercer.rb +30 -51
  121. data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
  122. data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
  123. data/lib/grape/validations/types/file.rb +22 -18
  124. data/lib/grape/validations/types/invalid_value.rb +24 -0
  125. data/lib/grape/validations/types/json.rb +47 -39
  126. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  127. data/lib/grape/validations/types/primitive_coercer.rb +67 -0
  128. data/lib/grape/validations/types/set_coercer.rb +40 -0
  129. data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
  130. data/lib/grape/validations/types.rb +26 -38
  131. data/lib/grape/validations/validator_factory.rb +8 -11
  132. data/lib/grape/validations/validators/all_or_none.rb +8 -12
  133. data/lib/grape/validations/validators/allow_blank.rb +4 -2
  134. data/lib/grape/validations/validators/as.rb +12 -0
  135. data/lib/grape/validations/validators/at_least_one_of.rb +7 -12
  136. data/lib/grape/validations/validators/base.rb +23 -15
  137. data/lib/grape/validations/validators/coerce.rb +47 -28
  138. data/lib/grape/validations/validators/default.rb +7 -6
  139. data/lib/grape/validations/validators/exactly_one_of.rb +10 -22
  140. data/lib/grape/validations/validators/except_values.rb +4 -2
  141. data/lib/grape/validations/validators/multiple_params_base.rb +19 -10
  142. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -17
  143. data/lib/grape/validations/validators/presence.rb +4 -1
  144. data/lib/grape/validations/validators/regexp.rb +5 -2
  145. data/lib/grape/validations/validators/same_as.rb +27 -0
  146. data/lib/grape/validations/validators/values.rb +29 -9
  147. data/lib/grape/validations.rb +2 -0
  148. data/lib/grape/version.rb +3 -1
  149. data/lib/grape.rb +107 -73
  150. data/spec/grape/api/custom_validations_spec.rb +6 -3
  151. data/spec/grape/api/deeply_included_options_spec.rb +2 -0
  152. data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
  153. data/spec/grape/api/inherited_helpers_spec.rb +116 -0
  154. data/spec/grape/api/instance_spec.rb +104 -0
  155. data/spec/grape/api/invalid_format_spec.rb +2 -0
  156. data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
  157. data/spec/grape/api/nested_helpers_spec.rb +2 -0
  158. data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
  159. data/spec/grape/api/parameters_modification_spec.rb +3 -1
  160. data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
  161. data/spec/grape/api/recognize_path_spec.rb +2 -0
  162. data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
  163. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
  164. data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
  165. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +49 -0
  166. data/spec/grape/api/shared_helpers_spec.rb +2 -0
  167. data/spec/grape/api_remount_spec.rb +473 -0
  168. data/spec/grape/api_spec.rb +775 -65
  169. data/spec/grape/config_spec.rb +19 -0
  170. data/spec/grape/dsl/callbacks_spec.rb +3 -1
  171. data/spec/grape/dsl/configuration_spec.rb +2 -0
  172. data/spec/grape/dsl/desc_spec.rb +42 -16
  173. data/spec/grape/dsl/headers_spec.rb +2 -0
  174. data/spec/grape/dsl/helpers_spec.rb +23 -2
  175. data/spec/grape/dsl/inside_route_spec.rb +185 -34
  176. data/spec/grape/dsl/logger_spec.rb +2 -0
  177. data/spec/grape/dsl/middleware_spec.rb +11 -1
  178. data/spec/grape/dsl/parameters_spec.rb +12 -9
  179. data/spec/grape/dsl/request_response_spec.rb +2 -0
  180. data/spec/grape/dsl/routing_spec.rb +13 -1
  181. data/spec/grape/dsl/settings_spec.rb +4 -2
  182. data/spec/grape/dsl/validations_spec.rb +2 -0
  183. data/spec/grape/endpoint/declared_spec.rb +848 -0
  184. data/spec/grape/endpoint_spec.rb +75 -515
  185. data/spec/grape/entity_spec.rb +19 -11
  186. data/spec/grape/exceptions/base_spec.rb +67 -0
  187. data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
  188. data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
  189. data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -1
  190. data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
  191. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -1
  192. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
  193. data/spec/grape/exceptions/missing_option_spec.rb +2 -1
  194. data/spec/grape/exceptions/unknown_options_spec.rb +3 -2
  195. data/spec/grape/exceptions/unknown_validator_spec.rb +2 -1
  196. data/spec/grape/exceptions/validation_errors_spec.rb +17 -4
  197. data/spec/grape/exceptions/validation_spec.rb +3 -1
  198. data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
  199. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
  200. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
  201. data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
  202. data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
  203. data/spec/grape/integration/rack_spec.rb +25 -7
  204. data/spec/grape/loading_spec.rb +2 -0
  205. data/spec/grape/middleware/auth/base_spec.rb +2 -0
  206. data/spec/grape/middleware/auth/dsl_spec.rb +6 -4
  207. data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
  208. data/spec/grape/middleware/base_spec.rb +10 -0
  209. data/spec/grape/middleware/error_spec.rb +4 -3
  210. data/spec/grape/middleware/exception_spec.rb +205 -55
  211. data/spec/grape/middleware/formatter_spec.rb +130 -15
  212. data/spec/grape/middleware/globals_spec.rb +2 -0
  213. data/spec/grape/middleware/stack_spec.rb +15 -1
  214. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
  215. data/spec/grape/middleware/versioner/header_spec.rb +10 -2
  216. data/spec/grape/middleware/versioner/param_spec.rb +4 -2
  217. data/spec/grape/middleware/versioner/path_spec.rb +4 -2
  218. data/spec/grape/middleware/versioner_spec.rb +2 -0
  219. data/spec/grape/named_api_spec.rb +21 -0
  220. data/spec/grape/parser_spec.rb +7 -5
  221. data/spec/grape/path_spec.rb +9 -7
  222. data/spec/grape/presenters/presenter_spec.rb +2 -0
  223. data/spec/grape/request_spec.rb +26 -0
  224. data/spec/grape/util/inheritable_setting_spec.rb +4 -2
  225. data/spec/grape/util/inheritable_values_spec.rb +2 -0
  226. data/spec/grape/util/reverse_stackable_values_spec.rb +15 -13
  227. data/spec/grape/util/stackable_values_spec.rb +16 -14
  228. data/spec/grape/util/strict_hash_configuration_spec.rb +3 -1
  229. data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
  230. data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
  231. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
  232. data/spec/grape/validations/params_scope_spec.rb +364 -7
  233. data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
  234. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  235. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  236. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  237. data/spec/grape/validations/types_spec.rb +9 -36
  238. data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
  239. data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
  240. data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
  241. data/spec/grape/validations/validators/coerce_spec.rb +558 -133
  242. data/spec/grape/validations/validators/default_spec.rb +212 -0
  243. data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
  244. data/spec/grape/validations/validators/except_values_spec.rb +6 -3
  245. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
  246. data/spec/grape/validations/validators/presence_spec.rb +30 -0
  247. data/spec/grape/validations/validators/regexp_spec.rb +2 -0
  248. data/spec/grape/validations/validators/same_as_spec.rb +65 -0
  249. data/spec/grape/validations/validators/values_spec.rb +73 -19
  250. data/spec/grape/validations_spec.rb +403 -53
  251. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  252. data/spec/integration/multi_json/json_spec.rb +2 -0
  253. data/spec/integration/multi_xml/xml_spec.rb +2 -0
  254. data/spec/shared/versioning_examples.rb +78 -18
  255. data/spec/spec_helper.rb +13 -2
  256. data/spec/support/basic_auth_encode_helpers.rb +3 -1
  257. data/spec/support/chunks.rb +14 -0
  258. data/spec/support/content_type_helpers.rb +3 -1
  259. data/spec/support/eager_load.rb +19 -0
  260. data/spec/support/endpoint_faker.rb +2 -0
  261. data/spec/support/file_streamer.rb +2 -0
  262. data/spec/support/integer_helpers.rb +2 -0
  263. data/spec/support/versioned_helpers.rb +8 -8
  264. metadata +176 -130
  265. data/Appraisals +0 -32
  266. data/Dangerfile +0 -1
  267. data/Gemfile +0 -34
  268. data/Gemfile.lock +0 -229
  269. data/Guardfile +0 -10
  270. data/RELEASING.md +0 -111
  271. data/Rakefile +0 -70
  272. data/benchmark/simple.rb +0 -27
  273. data/benchmark/simple_with_type_coercer.rb +0 -22
  274. data/gemfiles/multi_json.gemfile +0 -36
  275. data/gemfiles/multi_xml.gemfile +0 -36
  276. data/gemfiles/rack_1.5.2.gemfile +0 -36
  277. data/gemfiles/rack_edge.gemfile +0 -36
  278. data/gemfiles/rails_3.gemfile +0 -37
  279. data/gemfiles/rails_4.gemfile +0 -36
  280. data/gemfiles/rails_5.gemfile +0 -36
  281. data/gemfiles/rails_edge.gemfile +0 -36
  282. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  283. data/lib/grape/util/content_types.rb +0 -26
  284. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class RegexpValidator < Base
4
6
  def validate_param!(attr_name, params)
5
7
  return unless params.respond_to?(:key?) && params.key?(attr_name)
6
- return if Array.wrap(params[attr_name]).all? { |param| param.nil? || (param.to_s =~ (options_key?(:value) ? @option[:value] : @option)) }
7
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:regexp)
8
+ return if Array.wrap(params[attr_name]).all? { |param| param.nil? || param.to_s.match?((options_key?(:value) ? @option[:value] : @option)) }
9
+
10
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
8
11
  end
9
12
  end
10
13
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ class SameAsValidator < Base
6
+ def validate_param!(attr_name, params)
7
+ confirmation = options_key?(:value) ? @option[:value] : @option
8
+ return if params[attr_name] == params[confirmation]
9
+
10
+ raise Grape::Exceptions::Validation.new(
11
+ params: [@scope.full_name(attr_name)],
12
+ message: build_message
13
+ )
14
+ end
15
+
16
+ private
17
+
18
+ def build_message
19
+ if options_key?(:message)
20
+ @option[:message]
21
+ else
22
+ format I18n.t(:same_as, scope: 'grape.errors.messages'), parameter: @option
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module Validations
3
5
  class ValuesValidator < Base
4
- def initialize(attrs, options, required, scope, opts = {})
6
+ def initialize(attrs, options, required, scope, **opts)
5
7
  if options.is_a?(Hash)
6
8
  @excepts = options[:except]
7
9
  @values = options[:value]
@@ -11,6 +13,7 @@ module Grape
11
13
  'Use the except validator instead.' if @excepts
12
14
 
13
15
  raise ArgumentError, 'proc must be a Proc' if @proc && !@proc.is_a?(Proc)
16
+
14
17
  warn '[DEPRECATION] The values validator proc option is deprecated. ' \
15
18
  'The lambda expression can now be assigned directly to values.' if @proc
16
19
  else
@@ -24,32 +27,45 @@ module Grape
24
27
 
25
28
  def validate_param!(attr_name, params)
26
29
  return unless params.is_a?(Hash)
27
- return unless params[attr_name] || required_for_root_scope?
28
30
 
29
- param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
31
+ val = params[attr_name]
32
+
33
+ return if val.nil? && !required_for_root_scope?
34
+
35
+ # don't forget that +false.blank?+ is true
36
+ return if val != false && val.blank? && @allow_blank
37
+
38
+ param_array = val.nil? ? [nil] : Array.wrap(val)
30
39
 
31
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: except_message \
40
+ raise validation_exception(attr_name, except_message) \
32
41
  unless check_excepts(param_array)
33
42
 
34
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:values) \
35
- unless check_values(param_array)
43
+ raise validation_exception(attr_name, message(:values)) \
44
+ unless check_values(param_array, attr_name)
36
45
 
37
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:values) \
46
+ raise validation_exception(attr_name, message(:values)) \
38
47
  if @proc && !param_array.all? { |param| @proc.call(param) }
39
48
  end
40
49
 
41
50
  private
42
51
 
43
- def check_values(param_array)
52
+ def check_values(param_array, attr_name)
44
53
  values = @values.is_a?(Proc) && @values.arity.zero? ? @values.call : @values
45
54
  return true if values.nil?
46
- return param_array.all? { |param| values.call(param) } if values.is_a? Proc
55
+
56
+ begin
57
+ return param_array.all? { |param| values.call(param) } if values.is_a? Proc
58
+ rescue StandardError => e
59
+ warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
60
+ return false
61
+ end
47
62
  param_array.all? { |param| values.include?(param) }
48
63
  end
49
64
 
50
65
  def check_excepts(param_array)
51
66
  excepts = @excepts.is_a?(Proc) ? @excepts.call : @excepts
52
67
  return true if excepts.nil?
68
+
53
69
  param_array.none? { |param| excepts.include?(param) }
54
70
  end
55
71
 
@@ -61,6 +77,10 @@ module Grape
61
77
  def required_for_root_scope?
62
78
  @required && @scope.root?
63
79
  end
80
+
81
+ def validation_exception(attr_name, message)
82
+ Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
83
+ end
64
84
  end
65
85
  end
66
86
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  # Registry to store and locate known Validators.
3
5
  module Validations
data/lib/grape/version.rb CHANGED
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  # The current version of Grape.
3
- VERSION = '1.0.0'.freeze
5
+ VERSION = '1.6.0'
4
6
  end
data/lib/grape.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
  require 'rack'
3
5
  require 'rack/builder'
@@ -10,18 +12,17 @@ require 'active_support/core_ext/hash/indifferent_access'
10
12
  require 'active_support/core_ext/object/blank'
11
13
  require 'active_support/core_ext/array/extract_options'
12
14
  require 'active_support/core_ext/array/wrap'
15
+ require 'active_support/core_ext/array/conversions'
13
16
  require 'active_support/core_ext/hash/deep_merge'
14
17
  require 'active_support/core_ext/hash/reverse_merge'
15
18
  require 'active_support/core_ext/hash/except'
19
+ require 'active_support/core_ext/hash/slice'
16
20
  require 'active_support/core_ext/hash/conversions'
17
21
  require 'active_support/dependencies/autoload'
18
22
  require 'active_support/notifications'
19
23
  require 'i18n'
20
- require 'thread'
21
-
22
- require 'virtus'
23
24
 
24
- I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
25
+ I18n.load_path << File.expand_path('grape/locale/en.yml', __dir__)
25
26
 
26
27
  module Grape
27
28
  extend ::ActiveSupport::Autoload
@@ -29,12 +30,10 @@ module Grape
29
30
  eager_autoload do
30
31
  autoload :API
31
32
  autoload :Endpoint
32
- autoload :Router
33
33
 
34
34
  autoload :Namespace
35
35
 
36
36
  autoload :Path
37
-
38
37
  autoload :Cookies
39
38
  autoload :Validations
40
39
  autoload :ErrorFormatter
@@ -55,105 +54,125 @@ module Grape
55
54
 
56
55
  module Exceptions
57
56
  extend ::ActiveSupport::Autoload
58
- autoload :Base
59
- autoload :Validation
60
- autoload :ValidationArrayErrors
61
- autoload :ValidationErrors
62
- autoload :MissingVendorOption
63
- autoload :MissingMimeType
64
- autoload :MissingOption
65
- autoload :InvalidFormatter
66
- autoload :InvalidVersionerOption
67
- autoload :UnknownValidator
68
- autoload :UnknownOptions
69
- autoload :UnknownParameter
70
- autoload :InvalidWithOptionForRepresent
71
- autoload :IncompatibleOptionValues
72
- autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
73
- autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
74
- autoload :InvalidMessageBody
75
- autoload :InvalidAcceptHeader
76
- autoload :InvalidVersionHeader
77
- autoload :MethodNotAllowed
57
+ eager_autoload do
58
+ autoload :Base
59
+ autoload :Validation
60
+ autoload :ValidationArrayErrors
61
+ autoload :ValidationErrors
62
+ autoload :MissingVendorOption
63
+ autoload :MissingMimeType
64
+ autoload :MissingOption
65
+ autoload :InvalidFormatter
66
+ autoload :InvalidVersionerOption
67
+ autoload :UnknownValidator
68
+ autoload :UnknownOptions
69
+ autoload :UnknownParameter
70
+ autoload :InvalidWithOptionForRepresent
71
+ autoload :IncompatibleOptionValues
72
+ autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
73
+ autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
74
+ autoload :InvalidMessageBody
75
+ autoload :InvalidAcceptHeader
76
+ autoload :InvalidVersionHeader
77
+ autoload :MethodNotAllowed
78
+ autoload :InvalidResponse
79
+ autoload :EmptyMessageBody
80
+ end
78
81
  end
79
82
 
80
83
  module Extensions
81
84
  extend ::ActiveSupport::Autoload
82
-
83
- autoload :DeepMergeableHash
84
- autoload :DeepSymbolizeHash
85
- autoload :DeepHashWithIndifferentAccess
86
- autoload :Hash
87
-
85
+ eager_autoload do
86
+ autoload :DeepMergeableHash
87
+ autoload :DeepSymbolizeHash
88
+ autoload :Hash
89
+ end
88
90
  module ActiveSupport
89
91
  extend ::ActiveSupport::Autoload
90
-
91
- autoload :HashWithIndifferentAccess
92
+ eager_autoload do
93
+ autoload :HashWithIndifferentAccess
94
+ end
92
95
  end
93
96
 
94
97
  module Hashie
95
98
  extend ::ActiveSupport::Autoload
96
-
97
- autoload :Mash
99
+ eager_autoload do
100
+ autoload :Mash
101
+ end
98
102
  end
99
103
  end
100
104
 
101
105
  module Middleware
102
106
  extend ::ActiveSupport::Autoload
103
- autoload :Base
104
- autoload :Versioner
105
- autoload :Formatter
106
- autoload :Error
107
- autoload :Globals
108
- autoload :Stack
107
+ eager_autoload do
108
+ autoload :Base
109
+ autoload :Versioner
110
+ autoload :Formatter
111
+ autoload :Error
112
+ autoload :Globals
113
+ autoload :Stack
114
+ autoload :Helpers
115
+ end
109
116
 
110
117
  module Auth
111
118
  extend ::ActiveSupport::Autoload
112
- autoload :Base
113
- autoload :DSL
114
- autoload :StrategyInfo
115
- autoload :Strategies
119
+ eager_autoload do
120
+ autoload :Base
121
+ autoload :DSL
122
+ autoload :StrategyInfo
123
+ autoload :Strategies
124
+ end
116
125
  end
117
126
 
118
127
  module Versioner
119
128
  extend ::ActiveSupport::Autoload
120
- autoload :Path
121
- autoload :Header
122
- autoload :Param
123
- autoload :AcceptVersionHeader
129
+ eager_autoload do
130
+ autoload :Path
131
+ autoload :Header
132
+ autoload :Param
133
+ autoload :AcceptVersionHeader
134
+ end
124
135
  end
125
136
  end
126
137
 
127
138
  module Util
128
139
  extend ::ActiveSupport::Autoload
129
- autoload :InheritableValues
130
- autoload :StackableValues
131
- autoload :ReverseStackableValues
132
- autoload :InheritableSetting
133
- autoload :StrictHashConfiguration
134
- autoload :Registrable
140
+ eager_autoload do
141
+ autoload :InheritableValues
142
+ autoload :StackableValues
143
+ autoload :ReverseStackableValues
144
+ autoload :InheritableSetting
145
+ autoload :StrictHashConfiguration
146
+ autoload :Registrable
147
+ end
135
148
  end
136
149
 
137
150
  module ErrorFormatter
138
151
  extend ::ActiveSupport::Autoload
139
- autoload :Base
140
- autoload :Json
141
- autoload :Txt
142
- autoload :Xml
152
+ eager_autoload do
153
+ autoload :Base
154
+ autoload :Json
155
+ autoload :Txt
156
+ autoload :Xml
157
+ end
143
158
  end
144
159
 
145
160
  module Formatter
146
161
  extend ::ActiveSupport::Autoload
147
- autoload :Json
148
- autoload :SerializableHash
149
- autoload :Txt
150
- autoload :Xml
162
+ eager_autoload do
163
+ autoload :Json
164
+ autoload :SerializableHash
165
+ autoload :Txt
166
+ autoload :Xml
167
+ end
151
168
  end
152
169
 
153
170
  module Parser
154
171
  extend ::ActiveSupport::Autoload
155
- autoload :Json
156
- autoload :Xml
172
+ eager_autoload do
173
+ autoload :Json
174
+ autoload :Xml
175
+ end
157
176
  end
158
177
 
159
178
  module DSL
@@ -177,27 +196,41 @@ module Grape
177
196
 
178
197
  class API
179
198
  extend ::ActiveSupport::Autoload
180
- autoload :Helpers
199
+ eager_autoload do
200
+ autoload :Helpers
201
+ end
181
202
  end
182
203
 
183
204
  module Presenters
184
205
  extend ::ActiveSupport::Autoload
185
- autoload :Presenter
206
+ eager_autoload do
207
+ autoload :Presenter
208
+ end
186
209
  end
187
210
 
188
- module ServeFile
211
+ module ServeStream
189
212
  extend ::ActiveSupport::Autoload
190
- autoload :FileResponse
191
- autoload :FileBody
192
- autoload :SendfileResponse
213
+ eager_autoload do
214
+ autoload :FileBody
215
+ autoload :SendfileResponse
216
+ autoload :StreamResponse
217
+ end
193
218
  end
194
219
  end
195
220
 
196
- require 'grape/util/content_types'
221
+ require 'grape/config'
222
+ require 'grape/content_types'
223
+
224
+ require 'grape/util/lazy_value'
225
+ require 'grape/util/lazy_block'
226
+ require 'grape/util/endpoint_configuration'
197
227
 
198
228
  require 'grape/validations/validators/base'
199
229
  require 'grape/validations/attributes_iterator'
230
+ require 'grape/validations/single_attribute_iterator'
231
+ require 'grape/validations/multiple_attributes_iterator'
200
232
  require 'grape/validations/validators/allow_blank'
233
+ require 'grape/validations/validators/as'
201
234
  require 'grape/validations/validators/at_least_one_of'
202
235
  require 'grape/validations/validators/coerce'
203
236
  require 'grape/validations/validators/default'
@@ -205,6 +238,7 @@ require 'grape/validations/validators/exactly_one_of'
205
238
  require 'grape/validations/validators/mutual_exclusion'
206
239
  require 'grape/validations/validators/presence'
207
240
  require 'grape/validations/validators/regexp'
241
+ require 'grape/validations/validators/same_as'
208
242
  require 'grape/validations/validators/values'
209
243
  require 'grape/validations/validators/except_values'
210
244
  require 'grape/validations/params_scope'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Grape::Validations do
@@ -8,7 +10,8 @@ describe Grape::Validations do
8
10
  def validate_param!(attr_name, params)
9
11
  @option = params[:max].to_i if params.key?(:max)
10
12
  return if params[attr_name].length <= @option
11
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
13
+
14
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
12
15
  end
13
16
  end
14
17
  end
@@ -87,7 +90,7 @@ describe Grape::Validations do
87
90
  module CustomValidationsSpec
88
91
  class WithMessageKey < Grape::Validations::PresenceValidator
89
92
  def validate_param!(attr_name, _params)
90
- raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: :presence
93
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
91
94
  end
92
95
  end
93
96
  end
@@ -126,7 +129,7 @@ describe Grape::Validations do
126
129
  return unless @option
127
130
  # check if user is admin or not
128
131
  # as an example get a token from request and check if it's admin or not
129
- raise Grape::Exceptions::Validation, params: @attrs, message: 'Can not set Admin only field.' unless request.headers['X-Access-Token'] == 'admin'
132
+ raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
130
133
  end
131
134
  end
132
135
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  module DeeplyIncludedOptionsSpec
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Grape::API::Instance do
6
+ describe 'boolean constant' do
7
+ module DefinesBooleanInstanceSpec
8
+ class API < Grape::API
9
+ params do
10
+ requires :message, type: Boolean
11
+ end
12
+ post :echo do
13
+ { class: params[:message].class.name, value: params[:message] }
14
+ end
15
+ end
16
+ end
17
+
18
+ def app
19
+ DefinesBooleanInstanceSpec::API
20
+ end
21
+
22
+ let(:expected_body) do
23
+ { class: 'TrueClass', value: true }.to_s
24
+ end
25
+
26
+ it 'sets Boolean as a type' do
27
+ post '/echo?message=true'
28
+ expect(last_response.status).to eq(201)
29
+ expect(last_response.body).to eq expected_body
30
+ end
31
+
32
+ context 'Params endpoint type' do
33
+ subject { DefinesBooleanInstanceSpec::API.new.router.map['POST'].first.options[:params]['message'][:type] }
34
+ it 'params type is a boolean' do
35
+ is_expected.to eq 'Grape::API::Boolean'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Grape::API::Helpers do
6
+ let(:user) { 'Miguel Caneo' }
7
+ let(:id) { '42' }
8
+
9
+ module InheritedHelpersSpec
10
+ class SuperClass < Grape::API
11
+ helpers do
12
+ params(:superclass_params) { requires :id, type: String }
13
+
14
+ def current_user
15
+ params[:user]
16
+ end
17
+ end
18
+ end
19
+
20
+ class OverriddenSubClass < SuperClass
21
+ params { use :superclass_params }
22
+
23
+ helpers do
24
+ def current_user
25
+ "#{params[:user]} with id"
26
+ end
27
+ end
28
+
29
+ get 'resource' do
30
+ "#{current_user}: #{params['id']}"
31
+ end
32
+ end
33
+
34
+ class SubClass < SuperClass
35
+ params { use :superclass_params }
36
+
37
+ get 'resource' do
38
+ "#{current_user}: #{params['id']}"
39
+ end
40
+ end
41
+
42
+ class Example < SubClass
43
+ params { use :superclass_params }
44
+
45
+ get 'resource' do
46
+ "#{current_user}: #{params['id']}"
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'non overriding subclass' do
52
+ subject { InheritedHelpersSpec::SubClass }
53
+
54
+ def app
55
+ subject
56
+ end
57
+
58
+ context 'given expected params' do
59
+ it 'inherits helpers from a superclass' do
60
+ get '/resource', id: id, user: user
61
+ expect(last_response.body).to eq("#{user}: #{id}")
62
+ end
63
+ end
64
+
65
+ context 'with lack of expected params' do
66
+ it 'returns missing error' do
67
+ get '/resource'
68
+ expect(last_response.body).to eq('id is missing')
69
+ end
70
+ end
71
+ end
72
+
73
+ context 'overriding subclass' do
74
+ subject { InheritedHelpersSpec::OverriddenSubClass }
75
+
76
+ def app
77
+ subject
78
+ end
79
+
80
+ context 'given expected params' do
81
+ it 'overrides helpers from a superclass' do
82
+ get '/resource', id: id, user: user
83
+ expect(last_response.body).to eq("#{user} with id: #{id}")
84
+ end
85
+ end
86
+
87
+ context 'with lack of expected params' do
88
+ it 'returns missing error' do
89
+ get '/resource'
90
+ expect(last_response.body).to eq('id is missing')
91
+ end
92
+ end
93
+ end
94
+
95
+ context 'example subclass' do
96
+ subject { InheritedHelpersSpec::Example }
97
+
98
+ def app
99
+ subject
100
+ end
101
+
102
+ context 'given expected params' do
103
+ it 'inherits helpers from a superclass' do
104
+ get '/resource', id: id, user: user
105
+ expect(last_response.body).to eq("#{user}: #{id}")
106
+ end
107
+ end
108
+
109
+ context 'with lack of expected params' do
110
+ it 'returns missing error' do
111
+ get '/resource'
112
+ expect(last_response.body).to eq('id is missing')
113
+ end
114
+ end
115
+ end
116
+ end