grape 1.5.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +152 -21
  5. data/UPGRADING.md +86 -2
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +18 -13
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dry_types.rb +12 -0
  11. data/lib/grape/dsl/api.rb +0 -2
  12. data/lib/grape/dsl/callbacks.rb +0 -2
  13. data/lib/grape/dsl/configuration.rb +0 -2
  14. data/lib/grape/dsl/desc.rb +2 -19
  15. data/lib/grape/dsl/headers.rb +5 -2
  16. data/lib/grape/dsl/helpers.rb +7 -7
  17. data/lib/grape/dsl/inside_route.rb +43 -30
  18. data/lib/grape/dsl/middleware.rb +4 -6
  19. data/lib/grape/dsl/parameters.rb +8 -10
  20. data/lib/grape/dsl/request_response.rb +9 -8
  21. data/lib/grape/dsl/routing.rb +6 -4
  22. data/lib/grape/dsl/settings.rb +5 -7
  23. data/lib/grape/dsl/validations.rb +0 -15
  24. data/lib/grape/endpoint.rb +21 -36
  25. data/lib/grape/error_formatter/json.rb +9 -7
  26. data/lib/grape/error_formatter/xml.rb +2 -6
  27. data/lib/grape/exceptions/base.rb +2 -2
  28. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  29. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  30. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  31. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  32. data/lib/grape/exceptions/validation.rb +1 -6
  33. data/lib/grape/formatter/json.rb +1 -0
  34. data/lib/grape/formatter/serializable_hash.rb +2 -1
  35. data/lib/grape/formatter/xml.rb +1 -0
  36. data/lib/grape/locale/en.yml +9 -8
  37. data/lib/grape/middleware/auth/dsl.rb +7 -2
  38. data/lib/grape/middleware/base.rb +3 -1
  39. data/lib/grape/middleware/error.rb +2 -2
  40. data/lib/grape/middleware/formatter.rb +4 -4
  41. data/lib/grape/middleware/stack.rb +2 -2
  42. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  43. data/lib/grape/middleware/versioner/header.rb +6 -4
  44. data/lib/grape/middleware/versioner/param.rb +1 -0
  45. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  46. data/lib/grape/middleware/versioner/path.rb +2 -0
  47. data/lib/grape/parser/json.rb +1 -1
  48. data/lib/grape/parser/xml.rb +1 -1
  49. data/lib/grape/path.rb +1 -0
  50. data/lib/grape/request.rb +5 -0
  51. data/lib/grape/router/pattern.rb +1 -1
  52. data/lib/grape/router/route.rb +2 -2
  53. data/lib/grape/router.rb +6 -0
  54. data/lib/grape/util/inheritable_setting.rb +1 -3
  55. data/lib/grape/util/json.rb +2 -0
  56. data/lib/grape/util/lazy_value.rb +3 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_doc.rb +58 -0
  59. data/lib/grape/validations/params_scope.rb +137 -78
  60. data/lib/grape/validations/types/array_coercer.rb +0 -2
  61. data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
  62. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  63. data/lib/grape/validations/types/json.rb +2 -1
  64. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  65. data/lib/grape/validations/types/set_coercer.rb +0 -2
  66. data/lib/grape/validations/types.rb +98 -30
  67. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  68. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  69. data/lib/grape/validations/validators/as_validator.rb +14 -0
  70. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  71. data/lib/grape/validations/validators/base.rb +82 -70
  72. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  73. data/lib/grape/validations/validators/default_validator.rb +51 -0
  74. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  75. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  76. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  77. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  78. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  79. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  80. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  81. data/lib/grape/validations/validators/values_validator.rb +88 -0
  82. data/lib/grape/validations.rb +16 -6
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape.rb +70 -29
  85. data/spec/grape/api/custom_validations_spec.rb +116 -45
  86. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  87. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  88. data/spec/grape/api/documentation_spec.rb +59 -0
  89. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  90. data/spec/grape/api/instance_spec.rb +0 -1
  91. data/spec/grape/api/invalid_format_spec.rb +2 -2
  92. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  93. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  94. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  95. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  96. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  97. data/spec/grape/api/recognize_path_spec.rb +1 -3
  98. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  99. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  100. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  101. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  102. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  103. data/spec/grape/api_remount_spec.rb +16 -16
  104. data/spec/grape/api_spec.rb +527 -224
  105. data/spec/grape/config_spec.rb +0 -2
  106. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  107. data/spec/grape/dsl/configuration_spec.rb +0 -2
  108. data/spec/grape/dsl/desc_spec.rb +0 -2
  109. data/spec/grape/dsl/headers_spec.rb +39 -11
  110. data/spec/grape/dsl/helpers_spec.rb +3 -4
  111. data/spec/grape/dsl/inside_route_spec.rb +16 -16
  112. data/spec/grape/dsl/logger_spec.rb +15 -19
  113. data/spec/grape/dsl/middleware_spec.rb +2 -3
  114. data/spec/grape/dsl/parameters_spec.rb +2 -2
  115. data/spec/grape/dsl/request_response_spec.rb +7 -8
  116. data/spec/grape/dsl/routing_spec.rb +11 -10
  117. data/spec/grape/dsl/settings_spec.rb +0 -2
  118. data/spec/grape/dsl/validations_spec.rb +0 -17
  119. data/spec/grape/endpoint/declared_spec.rb +261 -16
  120. data/spec/grape/endpoint_spec.rb +98 -57
  121. data/spec/grape/entity_spec.rb +22 -23
  122. data/spec/grape/exceptions/base_spec.rb +16 -2
  123. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
  124. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
  125. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  126. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  127. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  128. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  129. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  130. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  131. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  132. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  133. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  134. data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
  135. data/spec/grape/exceptions/validation_spec.rb +5 -5
  136. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
  137. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
  138. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
  139. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  140. data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
  141. data/spec/grape/integration/rack_spec.rb +0 -2
  142. data/spec/grape/loading_spec.rb +8 -10
  143. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  144. data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
  145. data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
  146. data/spec/grape/middleware/base_spec.rb +24 -17
  147. data/spec/grape/middleware/error_spec.rb +8 -3
  148. data/spec/grape/middleware/exception_spec.rb +111 -163
  149. data/spec/grape/middleware/formatter_spec.rb +27 -8
  150. data/spec/grape/middleware/globals_spec.rb +7 -6
  151. data/spec/grape/middleware/stack_spec.rb +14 -14
  152. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
  153. data/spec/grape/middleware/versioner/header_spec.rb +30 -15
  154. data/spec/grape/middleware/versioner/param_spec.rb +7 -3
  155. data/spec/grape/middleware/versioner/path_spec.rb +5 -3
  156. data/spec/grape/middleware/versioner_spec.rb +1 -3
  157. data/spec/grape/named_api_spec.rb +0 -2
  158. data/spec/grape/parser_spec.rb +4 -2
  159. data/spec/grape/path_spec.rb +52 -54
  160. data/spec/grape/presenters/presenter_spec.rb +7 -8
  161. data/spec/grape/request_spec.rb +6 -6
  162. data/spec/grape/util/inheritable_setting_spec.rb +7 -8
  163. data/spec/grape/util/inheritable_values_spec.rb +3 -3
  164. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
  165. data/spec/grape/util/stackable_values_spec.rb +7 -6
  166. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  167. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  168. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  169. data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
  170. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  171. data/spec/grape/validations/params_scope_spec.rb +361 -96
  172. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  173. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  174. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  175. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  176. data/spec/grape/validations/types_spec.rb +36 -10
  177. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  178. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  179. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  180. data/spec/grape/validations/validators/coerce_spec.rb +99 -24
  181. data/spec/grape/validations/validators/default_spec.rb +72 -80
  182. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  183. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  184. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  185. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  186. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  187. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  188. data/spec/grape/validations/validators/values_spec.rb +182 -179
  189. data/spec/grape/validations_spec.rb +149 -80
  190. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  191. data/spec/integration/multi_json/json_spec.rb +1 -3
  192. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  193. data/spec/shared/versioning_examples.rb +12 -9
  194. data/spec/spec_helper.rb +21 -6
  195. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  196. metadata +125 -115
  197. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  198. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  199. data/lib/grape/validations/validators/as.rb +0 -16
  200. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  201. data/lib/grape/validations/validators/coerce.rb +0 -91
  202. data/lib/grape/validations/validators/default.rb +0 -48
  203. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  204. data/lib/grape/validations/validators/except_values.rb +0 -22
  205. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  206. data/lib/grape/validations/validators/presence.rb +0 -12
  207. data/lib/grape/validations/validators/regexp.rb +0 -13
  208. data/lib/grape/validations/validators/same_as.rb +0 -26
  209. data/lib/grape/validations/validators/values.rb +0 -83
  210. data/spec/support/eager_load.rb +0 -19
@@ -2,32 +2,36 @@
2
2
 
3
3
  module Grape
4
4
  module Validations
5
- class MultipleParamsBase < Base
6
- def validate!(params)
7
- attributes = MultipleAttributesIterator.new(self, @scope, params)
8
- array_errors = []
9
-
10
- attributes.each do |resource_params, skip_value|
11
- next if skip_value
12
- begin
13
- validate_params!(resource_params)
14
- rescue Grape::Exceptions::Validation => e
15
- array_errors << e
5
+ module Validators
6
+ class MultipleParamsBase < Base
7
+ def validate!(params)
8
+ attributes = MultipleAttributesIterator.new(self, @scope, params)
9
+ array_errors = []
10
+
11
+ attributes.each do |resource_params, skip_value|
12
+ next if skip_value
13
+
14
+ begin
15
+ validate_params!(resource_params)
16
+ rescue Grape::Exceptions::Validation => e
17
+ array_errors << e
18
+ end
16
19
  end
20
+
21
+ raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
17
22
  end
18
23
 
19
- raise Grape::Exceptions::ValidationArrayErrors, array_errors if array_errors.any?
20
- end
24
+ private
21
25
 
22
- private
26
+ def keys_in_common(resource_params)
27
+ return [] unless resource_params.is_a?(Hash)
23
28
 
24
- def keys_in_common(resource_params)
25
- return [] unless resource_params.is_a?(Hash)
26
- all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
27
- end
29
+ all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
30
+ end
28
31
 
29
- def all_keys
30
- attrs.map { |attr| @scope.full_name(attr) }
32
+ def all_keys
33
+ attrs.map { |attr| @scope.full_name(attr) }
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ class MutualExclusionValidator < MultipleParamsBase
7
+ def validate_params!(params)
8
+ keys = keys_in_common(params)
9
+ return if keys.length <= 1
10
+
11
+ raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ class PresenceValidator < Base
7
+ def validate_param!(attr_name, params)
8
+ return if params.respond_to?(:key?) && params.key?(attr_name)
9
+
10
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:presence))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ class RegexpValidator < Base
7
+ def validate_param!(attr_name, params)
8
+ return unless params.respond_to?(:key?) && params.key?(attr_name)
9
+ return if Array.wrap(params[attr_name]).all? { |param| param.nil? || param.to_s.match?((options_key?(:value) ? @option[:value] : @option)) }
10
+
11
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ class SameAsValidator < Base
7
+ def validate_param!(attr_name, params)
8
+ confirmation = options_key?(:value) ? @option[:value] : @option
9
+ return if params[attr_name] == params[confirmation]
10
+
11
+ raise Grape::Exceptions::Validation.new(
12
+ params: [@scope.full_name(attr_name)],
13
+ message: build_message
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def build_message
20
+ if options_key?(:message)
21
+ @option[:message]
22
+ else
23
+ format I18n.t(:same_as, scope: 'grape.errors.messages'), parameter: @option
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Validations
5
+ module Validators
6
+ class ValuesValidator < Base
7
+ def initialize(attrs, options, required, scope, **opts)
8
+ if options.is_a?(Hash)
9
+ @excepts = options[:except]
10
+ @values = options[:value]
11
+ @proc = options[:proc]
12
+
13
+ warn '[DEPRECATION] The values validator except option is deprecated. ' \
14
+ 'Use the except validator instead.' if @excepts
15
+
16
+ raise ArgumentError, 'proc must be a Proc' if @proc && !@proc.is_a?(Proc)
17
+
18
+ warn '[DEPRECATION] The values validator proc option is deprecated. ' \
19
+ 'The lambda expression can now be assigned directly to values.' if @proc
20
+ else
21
+ @excepts = nil
22
+ @values = nil
23
+ @proc = nil
24
+ @values = options
25
+ end
26
+ super
27
+ end
28
+
29
+ def validate_param!(attr_name, params)
30
+ return unless params.is_a?(Hash)
31
+
32
+ val = params[attr_name]
33
+
34
+ return if val.nil? && !required_for_root_scope?
35
+
36
+ # don't forget that +false.blank?+ is true
37
+ return if val != false && val.blank? && @allow_blank
38
+
39
+ param_array = val.nil? ? [nil] : Array.wrap(val)
40
+
41
+ raise validation_exception(attr_name, except_message) \
42
+ unless check_excepts(param_array)
43
+
44
+ raise validation_exception(attr_name, message(:values)) \
45
+ unless check_values(param_array, attr_name)
46
+
47
+ raise validation_exception(attr_name, message(:values)) \
48
+ if @proc && !param_array.all? { |param| @proc.call(param) }
49
+ end
50
+
51
+ private
52
+
53
+ def check_values(param_array, attr_name)
54
+ values = @values.is_a?(Proc) && @values.arity.zero? ? @values.call : @values
55
+ return true if values.nil?
56
+
57
+ begin
58
+ return param_array.all? { |param| values.call(param) } if values.is_a? Proc
59
+ rescue StandardError => e
60
+ warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
61
+ return false
62
+ end
63
+ param_array.all? { |param| values.include?(param) }
64
+ end
65
+
66
+ def check_excepts(param_array)
67
+ excepts = @excepts.is_a?(Proc) ? @excepts.call : @excepts
68
+ return true if excepts.nil?
69
+
70
+ param_array.none? { |param| excepts.include?(param) }
71
+ end
72
+
73
+ def except_message
74
+ options = instance_variable_get(:@option)
75
+ options_key?(:except_message) ? options[:except_message] : message(:except_values)
76
+ end
77
+
78
+ def required_for_root_scope?
79
+ @required && @scope.root?
80
+ end
81
+
82
+ def validation_exception(attr_name, message)
83
+ Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -3,22 +3,32 @@
3
3
  module Grape
4
4
  # Registry to store and locate known Validators.
5
5
  module Validations
6
- class << self
7
- attr_accessor :validators
8
- end
6
+ module_function
9
7
 
10
- self.validators = {}
8
+ def validators
9
+ @validators ||= {}
10
+ end
11
11
 
12
12
  # Register a new validator, so it can be used to validate parameters.
13
13
  # @param short_name [String] all lower-case, no spaces
14
14
  # @param klass [Class] the validator class. Should inherit from
15
15
  # Validations::Base.
16
- def self.register_validator(short_name, klass)
16
+ def register_validator(short_name, klass)
17
17
  validators[short_name] = klass
18
18
  end
19
19
 
20
- def self.deregister_validator(short_name)
20
+ def deregister_validator(short_name)
21
21
  validators.delete(short_name)
22
22
  end
23
+
24
+ # Find a validator and if not found will try to load it
25
+ def require_validator(short_name)
26
+ str_name = short_name.to_s
27
+ validators.fetch(str_name) do
28
+ Grape::Validations::Validators.const_get("#{str_name.camelize}Validator")
29
+ end
30
+ rescue NameError
31
+ raise Grape::Exceptions::UnknownValidator.new(short_name)
32
+ end
23
33
  end
24
34
  end
data/lib/grape/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Grape
4
4
  # The current version of Grape.
5
- VERSION = '1.5.2'
5
+ VERSION = '1.7.0'
6
6
  end
data/lib/grape.rb CHANGED
@@ -7,22 +7,27 @@ require 'rack/accept'
7
7
  require 'rack/auth/basic'
8
8
  require 'rack/auth/digest/md5'
9
9
  require 'set'
10
+ require 'bigdecimal'
11
+ require 'date'
12
+ require 'active_support'
13
+ require 'active_support/concern'
10
14
  require 'active_support/version'
11
- require 'active_support/core_ext/hash/indifferent_access'
12
- require 'active_support/core_ext/object/blank'
15
+ require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR > 6
16
+ require 'active_support/core_ext/array/conversions'
13
17
  require 'active_support/core_ext/array/extract_options'
14
18
  require 'active_support/core_ext/array/wrap'
15
- require 'active_support/core_ext/array/conversions'
19
+ require 'active_support/core_ext/hash/conversions'
16
20
  require 'active_support/core_ext/hash/deep_merge'
17
- require 'active_support/core_ext/hash/reverse_merge'
18
21
  require 'active_support/core_ext/hash/except'
22
+ require 'active_support/core_ext/hash/indifferent_access'
23
+ require 'active_support/core_ext/hash/reverse_merge'
19
24
  require 'active_support/core_ext/hash/slice'
20
- require 'active_support/core_ext/hash/conversions'
25
+ require 'active_support/core_ext/object/blank'
21
26
  require 'active_support/dependencies/autoload'
22
27
  require 'active_support/notifications'
23
28
  require 'i18n'
24
29
 
25
- I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
30
+ I18n.load_path << File.expand_path('grape/locale/en.yml', __dir__)
26
31
 
27
32
  module Grape
28
33
  extend ::ActiveSupport::Autoload
@@ -43,6 +48,7 @@ module Grape
43
48
  autoload :Env, 'grape/util/env'
44
49
  autoload :Json, 'grape/util/json'
45
50
  autoload :Xml, 'grape/util/xml'
51
+ autoload :DryTypes
46
52
  end
47
53
 
48
54
  module Http
@@ -69,13 +75,17 @@ module Grape
69
75
  autoload :UnknownParameter
70
76
  autoload :InvalidWithOptionForRepresent
71
77
  autoload :IncompatibleOptionValues
72
- autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
73
- autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
78
+ autoload :MissingGroupType
79
+ autoload :UnsupportedGroupType
74
80
  autoload :InvalidMessageBody
75
81
  autoload :InvalidAcceptHeader
76
82
  autoload :InvalidVersionHeader
77
83
  autoload :MethodNotAllowed
78
84
  autoload :InvalidResponse
85
+ autoload :EmptyMessageBody
86
+ autoload :TooManyMultipartFiles
87
+ autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
88
+ autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
79
89
  end
80
90
  end
81
91
 
@@ -215,6 +225,58 @@ module Grape
215
225
  autoload :StreamResponse
216
226
  end
217
227
  end
228
+
229
+ module Validations
230
+ extend ::ActiveSupport::Autoload
231
+
232
+ eager_autoload do
233
+ autoload :AttributesIterator
234
+ autoload :MultipleAttributesIterator
235
+ autoload :SingleAttributeIterator
236
+ autoload :Types
237
+ autoload :ParamsScope
238
+ autoload :ValidatorFactory
239
+ autoload :Base, 'grape/validations/validators/base'
240
+ end
241
+
242
+ module Types
243
+ extend ::ActiveSupport::Autoload
244
+
245
+ eager_autoload do
246
+ autoload :InvalidValue
247
+ autoload :DryTypeCoercer
248
+ autoload :ArrayCoercer
249
+ autoload :SetCoercer
250
+ autoload :PrimitiveCoercer
251
+ autoload :CustomTypeCoercer
252
+ autoload :CustomTypeCollectionCoercer
253
+ autoload :MultipleTypeCoercer
254
+ autoload :VariantCollectionCoercer
255
+ end
256
+ end
257
+
258
+ module Validators
259
+ extend ::ActiveSupport::Autoload
260
+
261
+ eager_autoload do
262
+ autoload :Base
263
+ autoload :MultipleParamsBase
264
+ autoload :AllOrNoneOfValidator
265
+ autoload :AllowBlankValidator
266
+ autoload :AsValidator
267
+ autoload :AtLeastOneOfValidator
268
+ autoload :CoerceValidator
269
+ autoload :DefaultValidator
270
+ autoload :ExactlyOneOfValidator
271
+ autoload :ExceptValuesValidator
272
+ autoload :MutualExclusionValidator
273
+ autoload :PresenceValidator
274
+ autoload :RegexpValidator
275
+ autoload :SameAsValidator
276
+ autoload :ValuesValidator
277
+ end
278
+ end
279
+ end
218
280
  end
219
281
 
220
282
  require 'grape/config'
@@ -224,25 +286,4 @@ require 'grape/util/lazy_value'
224
286
  require 'grape/util/lazy_block'
225
287
  require 'grape/util/endpoint_configuration'
226
288
 
227
- require 'grape/validations/validators/base'
228
- require 'grape/validations/attributes_iterator'
229
- require 'grape/validations/single_attribute_iterator'
230
- require 'grape/validations/multiple_attributes_iterator'
231
- require 'grape/validations/validators/allow_blank'
232
- require 'grape/validations/validators/as'
233
- require 'grape/validations/validators/at_least_one_of'
234
- require 'grape/validations/validators/coerce'
235
- require 'grape/validations/validators/default'
236
- require 'grape/validations/validators/exactly_one_of'
237
- require 'grape/validations/validators/mutual_exclusion'
238
- require 'grape/validations/validators/presence'
239
- require 'grape/validations/validators/regexp'
240
- require 'grape/validations/validators/same_as'
241
- require 'grape/validations/validators/values'
242
- require 'grape/validations/validators/except_values'
243
- require 'grape/validations/params_scope'
244
- require 'grape/validations/validators/all_or_none'
245
- require 'grape/validations/types'
246
- require 'grape/validations/validator_factory'
247
-
248
289
  require 'grape/version'
@@ -1,20 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations do
6
- context 'using a custom length validator' do
7
- before do
8
- module CustomValidationsSpec
9
- class DefaultLength < Grape::Validations::Base
10
- def validate_param!(attr_name, params)
11
- @option = params[:max].to_i if params.key?(:max)
12
- return if params[attr_name].length <= @option
13
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
14
- end
4
+ context 'deprecated Grape::Validations::Base' do
5
+ subject do
6
+ Class.new(Grape::API) do
7
+ params do
8
+ requires :text, validator_with_old_base: true
9
+ end
10
+ get do
11
+ end
12
+ end
13
+ end
14
+
15
+ let(:validator_with_old_base) do
16
+ Class.new(Grape::Validations::Base) do
17
+ def validate_param!(_attr_name, _params)
18
+ true
15
19
  end
16
20
  end
17
21
  end
22
+
23
+ before do
24
+ described_class.register_validator('validator_with_old_base', validator_with_old_base)
25
+ allow(Warning).to receive(:warn)
26
+ end
27
+
28
+ after do
29
+ described_class.deregister_validator('validator_with_old_base')
30
+ end
31
+
32
+ def app
33
+ subject
34
+ end
35
+
36
+ it 'puts a deprecation warning' do
37
+ expect(Warning).to receive(:warn) do |message|
38
+ expect(message).to include('`Grape::Validations::Base` is deprecated')
39
+ end
40
+
41
+ get '/'
42
+ end
43
+ end
44
+
45
+ context 'using a custom length validator' do
18
46
  subject do
19
47
  Class.new(Grape::API) do
20
48
  params do
@@ -26,6 +54,25 @@ describe Grape::Validations do
26
54
  end
27
55
  end
28
56
 
57
+ let(:default_length_validator) do
58
+ Class.new(Grape::Validations::Validators::Base) do
59
+ def validate_param!(attr_name, params)
60
+ @option = params[:max].to_i if params.key?(:max)
61
+ return if params[attr_name].length <= @option
62
+
63
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
64
+ end
65
+ end
66
+ end
67
+
68
+ before do
69
+ described_class.register_validator('default_length', default_length_validator)
70
+ end
71
+
72
+ after do
73
+ described_class.deregister_validator('default_length')
74
+ end
75
+
29
76
  def app
30
77
  subject
31
78
  end
@@ -35,11 +82,13 @@ describe Grape::Validations do
35
82
  expect(last_response.status).to eq 200
36
83
  expect(last_response.body).to eq 'bacon'
37
84
  end
85
+
38
86
  it 'over 140 characters' do
39
87
  get '/', text: 'a' * 141
40
88
  expect(last_response.status).to eq 400
41
89
  expect(last_response.body).to eq 'text must be at the most 140 characters long'
42
90
  end
91
+
43
92
  it 'specified in the query string' do
44
93
  get '/', text: 'a' * 141, max: 141
45
94
  expect(last_response.status).to eq 200
@@ -48,15 +97,6 @@ describe Grape::Validations do
48
97
  end
49
98
 
50
99
  context 'using a custom body-only validator' do
51
- before do
52
- module CustomValidationsSpec
53
- class InBody < Grape::Validations::PresenceValidator
54
- def validate(request)
55
- validate!(request.env['api.request.body'])
56
- end
57
- end
58
- end
59
- end
60
100
  subject do
61
101
  Class.new(Grape::API) do
62
102
  params do
@@ -68,6 +108,22 @@ describe Grape::Validations do
68
108
  end
69
109
  end
70
110
 
111
+ let(:in_body_validator) do
112
+ Class.new(Grape::Validations::Validators::PresenceValidator) do
113
+ def validate(request)
114
+ validate!(request.env['api.request.body'])
115
+ end
116
+ end
117
+ end
118
+
119
+ before do
120
+ described_class.register_validator('in_body', in_body_validator)
121
+ end
122
+
123
+ after do
124
+ described_class.deregister_validator('in_body')
125
+ end
126
+
71
127
  def app
72
128
  subject
73
129
  end
@@ -77,6 +133,7 @@ describe Grape::Validations do
77
133
  expect(last_response.status).to eq 200
78
134
  expect(last_response.body).to eq 'bacon'
79
135
  end
136
+
80
137
  it 'ignores field in query' do
81
138
  get '/', nil, text: 'abc'
82
139
  expect(last_response.status).to eq 400
@@ -85,15 +142,6 @@ describe Grape::Validations do
85
142
  end
86
143
 
87
144
  context 'using a custom validator with message_key' do
88
- before do
89
- module CustomValidationsSpec
90
- class WithMessageKey < Grape::Validations::PresenceValidator
91
- def validate_param!(attr_name, _params)
92
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
93
- end
94
- end
95
- end
96
- end
97
145
  subject do
98
146
  Class.new(Grape::API) do
99
147
  params do
@@ -105,6 +153,22 @@ describe Grape::Validations do
105
153
  end
106
154
  end
107
155
 
156
+ let(:message_key_validator) do
157
+ Class.new(Grape::Validations::Validators::PresenceValidator) do
158
+ def validate_param!(attr_name, _params)
159
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
160
+ end
161
+ end
162
+ end
163
+
164
+ before do
165
+ described_class.register_validator('with_message_key', message_key_validator)
166
+ end
167
+
168
+ after do
169
+ described_class.deregister_validator('with_message_key')
170
+ end
171
+
108
172
  def app
109
173
  subject
110
174
  end
@@ -117,22 +181,6 @@ describe Grape::Validations do
117
181
  end
118
182
 
119
183
  context 'using a custom request/param validator' do
120
- before do
121
- module CustomValidationsSpec
122
- class Admin < Grape::Validations::Base
123
- def validate(request)
124
- # return if the param we are checking was not in request
125
- # @attrs is a list containing the attribute we are currently validating
126
- return unless request.params.key? @attrs.first
127
- # check if admin flag is set to true
128
- return unless @option
129
- # check if user is admin or not
130
- # as an example get a token from request and check if it's admin or not
131
- raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
132
- end
133
- end
134
- end
135
- end
136
184
  subject do
137
185
  Class.new(Grape::API) do
138
186
  params do
@@ -146,6 +194,29 @@ describe Grape::Validations do
146
194
  end
147
195
  end
148
196
 
197
+ let(:admin_validator) do
198
+ Class.new(Grape::Validations::Validators::Base) do
199
+ def validate(request)
200
+ # return if the param we are checking was not in request
201
+ # @attrs is a list containing the attribute we are currently validating
202
+ return unless request.params.key? @attrs.first
203
+ # check if admin flag is set to true
204
+ return unless @option
205
+ # check if user is admin or not
206
+ # as an example get a token from request and check if it's admin or not
207
+ raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
208
+ end
209
+ end
210
+ end
211
+
212
+ before do
213
+ described_class.register_validator('admin', admin_validator)
214
+ end
215
+
216
+ after do
217
+ described_class.deregister_validator('admin')
218
+ end
219
+
149
220
  def app
150
221
  subject
151
222
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module DeeplyIncludedOptionsSpec
6
4
  module Defaults
7
5
  extend ActiveSupport::Concern
@@ -41,18 +39,18 @@ describe Grape::API do
41
39
 
42
40
  it 'works for unspecified format' do
43
41
  get '/users'
44
- expect(last_response.status).to eql 200
42
+ expect(last_response.status).to be 200
45
43
  expect(last_response.content_type).to eql 'application/json'
46
44
  end
47
45
 
48
46
  it 'works for specified format' do
49
47
  get '/users.json'
50
- expect(last_response.status).to eql 200
48
+ expect(last_response.status).to be 200
51
49
  expect(last_response.content_type).to eql 'application/json'
52
50
  end
53
51
 
54
52
  it "doesn't work for format different than specified" do
55
53
  get '/users.txt'
56
- expect(last_response.status).to eql 404
54
+ expect(last_response.status).to be 404
57
55
  end
58
56
  end