grape 1.3.3 → 1.6.2

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -2
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +135 -23
  5. data/UPGRADING.md +237 -46
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +34 -42
  8. data/lib/grape/api.rb +21 -16
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dsl/callbacks.rb +1 -1
  11. data/lib/grape/dsl/desc.rb +3 -5
  12. data/lib/grape/dsl/headers.rb +5 -2
  13. data/lib/grape/dsl/helpers.rb +8 -5
  14. data/lib/grape/dsl/inside_route.rb +72 -53
  15. data/lib/grape/dsl/middleware.rb +4 -4
  16. data/lib/grape/dsl/parameters.rb +11 -7
  17. data/lib/grape/dsl/request_response.rb +9 -6
  18. data/lib/grape/dsl/routing.rb +8 -9
  19. data/lib/grape/dsl/settings.rb +5 -5
  20. data/lib/grape/dsl/validations.rb +18 -1
  21. data/lib/grape/eager_load.rb +1 -1
  22. data/lib/grape/endpoint.rb +29 -42
  23. data/lib/grape/error_formatter/json.rb +2 -6
  24. data/lib/grape/error_formatter/xml.rb +2 -6
  25. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  26. data/lib/grape/exceptions/validation.rb +2 -3
  27. data/lib/grape/exceptions/validation_errors.rb +1 -1
  28. data/lib/grape/formatter/json.rb +1 -0
  29. data/lib/grape/formatter/serializable_hash.rb +2 -1
  30. data/lib/grape/formatter/xml.rb +1 -0
  31. data/lib/grape/locale/en.yml +1 -1
  32. data/lib/grape/middleware/auth/base.rb +3 -3
  33. data/lib/grape/middleware/auth/dsl.rb +7 -1
  34. data/lib/grape/middleware/base.rb +6 -3
  35. data/lib/grape/middleware/error.rb +11 -13
  36. data/lib/grape/middleware/formatter.rb +7 -7
  37. data/lib/grape/middleware/stack.rb +10 -3
  38. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  39. data/lib/grape/middleware/versioner/header.rb +6 -4
  40. data/lib/grape/middleware/versioner/param.rb +1 -0
  41. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  42. data/lib/grape/middleware/versioner/path.rb +2 -0
  43. data/lib/grape/parser/json.rb +1 -1
  44. data/lib/grape/parser/xml.rb +1 -1
  45. data/lib/grape/path.rb +1 -0
  46. data/lib/grape/request.rb +4 -1
  47. data/lib/grape/router/attribute_translator.rb +3 -3
  48. data/lib/grape/router/pattern.rb +1 -1
  49. data/lib/grape/router/route.rb +2 -2
  50. data/lib/grape/router.rb +31 -30
  51. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  52. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  53. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  54. data/lib/grape/util/base_inheritable.rb +2 -2
  55. data/lib/grape/util/inheritable_setting.rb +1 -3
  56. data/lib/grape/util/lazy_value.rb +4 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_iterator.rb +8 -0
  59. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  60. data/lib/grape/validations/params_scope.rb +97 -62
  61. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  62. data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
  63. data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
  64. data/lib/grape/validations/types/invalid_value.rb +24 -0
  65. data/lib/grape/validations/types/json.rb +2 -1
  66. data/lib/grape/validations/types/primitive_coercer.rb +4 -5
  67. data/lib/grape/validations/types.rb +1 -4
  68. data/lib/grape/validations/validator_factory.rb +1 -1
  69. data/lib/grape/validations/validators/all_or_none.rb +8 -5
  70. data/lib/grape/validations/validators/allow_blank.rb +9 -7
  71. data/lib/grape/validations/validators/as.rb +6 -8
  72. data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
  73. data/lib/grape/validations/validators/base.rb +74 -69
  74. data/lib/grape/validations/validators/coerce.rb +63 -76
  75. data/lib/grape/validations/validators/default.rb +36 -34
  76. data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
  77. data/lib/grape/validations/validators/except_values.rb +13 -11
  78. data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
  79. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
  80. data/lib/grape/validations/validators/presence.rb +7 -4
  81. data/lib/grape/validations/validators/regexp.rb +8 -5
  82. data/lib/grape/validations/validators/same_as.rb +18 -15
  83. data/lib/grape/validations/validators/values.rb +61 -56
  84. data/lib/grape/validations.rb +6 -0
  85. data/lib/grape/version.rb +1 -1
  86. data/lib/grape.rb +7 -3
  87. data/spec/grape/api/custom_validations_spec.rb +77 -45
  88. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  89. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  90. data/spec/grape/api/invalid_format_spec.rb +2 -0
  91. data/spec/grape/api/recognize_path_spec.rb +1 -1
  92. data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
  93. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  94. data/spec/grape/api_remount_spec.rb +25 -19
  95. data/spec/grape/api_spec.rb +576 -211
  96. data/spec/grape/dsl/callbacks_spec.rb +2 -1
  97. data/spec/grape/dsl/headers_spec.rb +39 -9
  98. data/spec/grape/dsl/helpers_spec.rb +3 -2
  99. data/spec/grape/dsl/inside_route_spec.rb +185 -34
  100. data/spec/grape/dsl/logger_spec.rb +16 -18
  101. data/spec/grape/dsl/middleware_spec.rb +2 -1
  102. data/spec/grape/dsl/parameters_spec.rb +2 -0
  103. data/spec/grape/dsl/request_response_spec.rb +1 -0
  104. data/spec/grape/dsl/routing_spec.rb +10 -7
  105. data/spec/grape/endpoint/declared_spec.rb +848 -0
  106. data/spec/grape/endpoint_spec.rb +77 -589
  107. data/spec/grape/entity_spec.rb +29 -23
  108. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  109. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  110. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  111. data/spec/grape/exceptions/validation_spec.rb +5 -3
  112. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  113. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  114. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  115. data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
  116. data/spec/grape/loading_spec.rb +8 -8
  117. data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
  118. data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
  119. data/spec/grape/middleware/base_spec.rb +24 -15
  120. data/spec/grape/middleware/error_spec.rb +3 -3
  121. data/spec/grape/middleware/exception_spec.rb +111 -161
  122. data/spec/grape/middleware/formatter_spec.rb +28 -7
  123. data/spec/grape/middleware/globals_spec.rb +7 -4
  124. data/spec/grape/middleware/stack_spec.rb +15 -12
  125. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  126. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  127. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  128. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  129. data/spec/grape/middleware/versioner_spec.rb +1 -1
  130. data/spec/grape/parser_spec.rb +4 -0
  131. data/spec/grape/path_spec.rb +52 -52
  132. data/spec/grape/presenters/presenter_spec.rb +7 -6
  133. data/spec/grape/request_spec.rb +6 -4
  134. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  135. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  136. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  137. data/spec/grape/util/stackable_values_spec.rb +7 -5
  138. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  139. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
  140. data/spec/grape/validations/params_scope_spec.rb +72 -10
  141. data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
  142. data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
  143. data/spec/grape/validations/types_spec.rb +8 -8
  144. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  145. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  146. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  147. data/spec/grape/validations/validators/coerce_spec.rb +248 -33
  148. data/spec/grape/validations/validators/default_spec.rb +121 -78
  149. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  150. data/spec/grape/validations/validators/except_values_spec.rb +4 -3
  151. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  152. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  153. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  154. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  155. data/spec/grape/validations/validators/values_spec.rb +183 -178
  156. data/spec/grape/validations_spec.rb +342 -29
  157. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  158. data/spec/integration/multi_json/json_spec.rb +1 -1
  159. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  160. data/spec/shared/versioning_examples.rb +32 -29
  161. data/spec/spec_helper.rb +12 -12
  162. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  163. data/spec/support/chunks.rb +14 -0
  164. data/spec/support/versioned_helpers.rb +4 -6
  165. metadata +110 -102
@@ -4,12 +4,15 @@ require 'grape/validations/validators/multiple_params_base'
4
4
 
5
5
  module Grape
6
6
  module Validations
7
- class ExactlyOneOfValidator < MultipleParamsBase
8
- def validate_params!(params)
9
- keys = keys_in_common(params)
10
- return if keys.length == 1
11
- raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:exactly_one)) if keys.length.zero?
12
- raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
7
+ module Validators
8
+ class ExactlyOneOfValidator < MultipleParamsBase
9
+ def validate_params!(params)
10
+ keys = keys_in_common(params)
11
+ return if keys.length == 1
12
+ raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:exactly_one)) if keys.length.zero?
13
+
14
+ raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
15
+ end
13
16
  end
14
17
  end
15
18
  end
@@ -2,20 +2,22 @@
2
2
 
3
3
  module Grape
4
4
  module Validations
5
- class ExceptValuesValidator < Base
6
- def initialize(attrs, options, required, scope, opts = {})
7
- @except = options.is_a?(Hash) ? options[:value] : options
8
- super
9
- end
5
+ module Validators
6
+ class ExceptValuesValidator < Base
7
+ def initialize(attrs, options, required, scope, **opts)
8
+ @except = options.is_a?(Hash) ? options[:value] : options
9
+ super
10
+ end
10
11
 
11
- def validate_param!(attr_name, params)
12
- return unless params.respond_to?(:key?) && params.key?(attr_name)
12
+ def validate_param!(attr_name, params)
13
+ return unless params.respond_to?(:key?) && params.key?(attr_name)
13
14
 
14
- excepts = @except.is_a?(Proc) ? @except.call : @except
15
- return if excepts.nil?
15
+ excepts = @except.is_a?(Proc) ? @except.call : @except
16
+ return if excepts.nil?
16
17
 
17
- param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
18
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:except_values)) if param_array.any? { |param| excepts.include?(param) }
18
+ param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
19
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:except_values)) if param_array.any? { |param| excepts.include?(param) }
20
+ end
19
21
  end
20
22
  end
21
23
  end
@@ -2,31 +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|
11
- begin
12
- validate_params!(resource_params)
13
- rescue Grape::Exceptions::Validation => e
14
- 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
15
19
  end
20
+
21
+ raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
16
22
  end
17
23
 
18
- raise Grape::Exceptions::ValidationArrayErrors, array_errors if array_errors.any?
19
- end
24
+ private
20
25
 
21
- private
26
+ def keys_in_common(resource_params)
27
+ return [] unless resource_params.is_a?(Hash)
22
28
 
23
- def keys_in_common(resource_params)
24
- return [] unless resource_params.is_a?(Hash)
25
- all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
26
- end
29
+ all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
30
+ end
27
31
 
28
- def all_keys
29
- attrs.map { |attr| @scope.full_name(attr) }
32
+ def all_keys
33
+ attrs.map { |attr| @scope.full_name(attr) }
34
+ end
30
35
  end
31
36
  end
32
37
  end
@@ -4,11 +4,14 @@ require 'grape/validations/validators/multiple_params_base'
4
4
 
5
5
  module Grape
6
6
  module Validations
7
- class MutualExclusionValidator < MultipleParamsBase
8
- def validate_params!(params)
9
- keys = keys_in_common(params)
10
- return if keys.length <= 1
11
- raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
7
+ module Validators
8
+ class MutualExclusionValidator < MultipleParamsBase
9
+ def validate_params!(params)
10
+ keys = keys_in_common(params)
11
+ return if keys.length <= 1
12
+
13
+ raise Grape::Exceptions::Validation.new(params: keys, message: message(:mutual_exclusion))
14
+ end
12
15
  end
13
16
  end
14
17
  end
@@ -2,10 +2,13 @@
2
2
 
3
3
  module Grape
4
4
  module Validations
5
- class PresenceValidator < Base
6
- def validate_param!(attr_name, params)
7
- return if params.respond_to?(:key?) && params.key?(attr_name)
8
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:presence))
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
9
12
  end
10
13
  end
11
14
  end
@@ -2,11 +2,14 @@
2
2
 
3
3
  module Grape
4
4
  module Validations
5
- class RegexpValidator < Base
6
- def validate_param!(attr_name, params)
7
- return unless params.respond_to?(:key?) && params.key?(attr_name)
8
- return if Array.wrap(params[attr_name]).all? { |param| param.nil? || param.to_s.match?((options_key?(:value) ? @option[:value] : @option)) }
9
- raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:regexp))
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
10
13
  end
11
14
  end
12
15
  end
@@ -2,23 +2,26 @@
2
2
 
3
3
  module Grape
4
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
- raise Grape::Exceptions::Validation.new(
10
- params: [@scope.full_name(attr_name)],
11
- message: build_message
12
- )
13
- end
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
14
16
 
15
- private
17
+ private
16
18
 
17
- def build_message
18
- if options_key?(:message)
19
- @option[:message]
20
- else
21
- format I18n.t(:same_as, scope: 'grape.errors.messages'), parameter: @option
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
22
25
  end
23
26
  end
24
27
  end
@@ -2,81 +2,86 @@
2
2
 
3
3
  module Grape
4
4
  module Validations
5
- class ValuesValidator < Base
6
- def initialize(attrs, options, required, scope, opts = {})
7
- if options.is_a?(Hash)
8
- @excepts = options[:except]
9
- @values = options[:value]
10
- @proc = options[:proc]
11
-
12
- warn '[DEPRECATION] The values validator except option is deprecated. ' \
13
- 'Use the except validator instead.' if @excepts
14
-
15
- raise ArgumentError, 'proc must be a Proc' if @proc && !@proc.is_a?(Proc)
16
- warn '[DEPRECATION] The values validator proc option is deprecated. ' \
17
- 'The lambda expression can now be assigned directly to values.' if @proc
18
- else
19
- @excepts = nil
20
- @values = nil
21
- @proc = nil
22
- @values = options
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
23
27
  end
24
- super
25
- end
26
28
 
27
- def validate_param!(attr_name, params)
28
- return unless params.is_a?(Hash)
29
+ def validate_param!(attr_name, params)
30
+ return unless params.is_a?(Hash)
29
31
 
30
- val = params[attr_name]
32
+ val = params[attr_name]
31
33
 
32
- return if val.nil? && !required_for_root_scope?
34
+ return if val.nil? && !required_for_root_scope?
33
35
 
34
- # don't forget that +false.blank?+ is true
35
- return if val != false && val.blank? && @allow_blank
36
+ # don't forget that +false.blank?+ is true
37
+ return if val != false && val.blank? && @allow_blank
36
38
 
37
- param_array = val.nil? ? [nil] : Array.wrap(val)
39
+ param_array = val.nil? ? [nil] : Array.wrap(val)
38
40
 
39
- raise validation_exception(attr_name, except_message) \
41
+ raise validation_exception(attr_name, except_message) \
40
42
  unless check_excepts(param_array)
41
43
 
42
- raise validation_exception(attr_name, message(:values)) \
44
+ raise validation_exception(attr_name, message(:values)) \
43
45
  unless check_values(param_array, attr_name)
44
46
 
45
- raise validation_exception(attr_name, message(:values)) \
47
+ raise validation_exception(attr_name, message(:values)) \
46
48
  if @proc && !param_array.all? { |param| @proc.call(param) }
47
- end
49
+ end
50
+
51
+ private
48
52
 
49
- private
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?
50
56
 
51
- def check_values(param_array, attr_name)
52
- values = @values.is_a?(Proc) && @values.arity.zero? ? @values.call : @values
53
- return true if values.nil?
54
- begin
55
- return param_array.all? { |param| values.call(param) } if values.is_a? Proc
56
- rescue StandardError => e
57
- warn "Error '#{e}' raised while validating attribute '#{attr_name}'"
58
- return false
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) }
59
64
  end
60
- param_array.all? { |param| values.include?(param) }
61
- end
62
65
 
63
- def check_excepts(param_array)
64
- excepts = @excepts.is_a?(Proc) ? @excepts.call : @excepts
65
- return true if excepts.nil?
66
- param_array.none? { |param| excepts.include?(param) }
67
- end
66
+ def check_excepts(param_array)
67
+ excepts = @excepts.is_a?(Proc) ? @excepts.call : @excepts
68
+ return true if excepts.nil?
68
69
 
69
- def except_message
70
- options = instance_variable_get(:@option)
71
- options_key?(:except_message) ? options[:except_message] : message(:except_values)
72
- end
70
+ param_array.none? { |param| excepts.include?(param) }
71
+ end
73
72
 
74
- def required_for_root_scope?
75
- @required && @scope.root?
76
- end
73
+ def except_message
74
+ options = instance_variable_get(:@option)
75
+ options_key?(:except_message) ? options[:except_message] : message(:except_values)
76
+ end
77
77
 
78
- def validation_exception(attr_name, message)
79
- Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message)
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
80
85
  end
81
86
  end
82
87
  end
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'grape/validations/attributes_iterator'
4
+ require 'grape/validations/single_attribute_iterator'
5
+ require 'grape/validations/multiple_attributes_iterator'
6
+ require 'grape/validations/params_scope'
7
+ require 'grape/validations/types'
8
+
3
9
  module Grape
4
10
  # Registry to store and locate known Validators.
5
11
  module Validations
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.3.3'
5
+ VERSION = '1.6.2'
6
6
  end
data/lib/grape.rb CHANGED
@@ -7,11 +7,14 @@ require 'rack/accept'
7
7
  require 'rack/auth/basic'
8
8
  require 'rack/auth/digest/md5'
9
9
  require 'set'
10
+ require 'active_support'
10
11
  require 'active_support/version'
12
+ require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR > 6
11
13
  require 'active_support/core_ext/hash/indifferent_access'
12
14
  require 'active_support/core_ext/object/blank'
13
15
  require 'active_support/core_ext/array/extract_options'
14
16
  require 'active_support/core_ext/array/wrap'
17
+ require 'active_support/core_ext/array/conversions'
15
18
  require 'active_support/core_ext/hash/deep_merge'
16
19
  require 'active_support/core_ext/hash/reverse_merge'
17
20
  require 'active_support/core_ext/hash/except'
@@ -21,7 +24,7 @@ require 'active_support/dependencies/autoload'
21
24
  require 'active_support/notifications'
22
25
  require 'i18n'
23
26
 
24
- I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
27
+ I18n.load_path << File.expand_path('grape/locale/en.yml', __dir__)
25
28
 
26
29
  module Grape
27
30
  extend ::ActiveSupport::Autoload
@@ -75,6 +78,7 @@ module Grape
75
78
  autoload :InvalidVersionHeader
76
79
  autoload :MethodNotAllowed
77
80
  autoload :InvalidResponse
81
+ autoload :EmptyMessageBody
78
82
  end
79
83
  end
80
84
 
@@ -206,12 +210,12 @@ module Grape
206
210
  end
207
211
  end
208
212
 
209
- module ServeFile
213
+ module ServeStream
210
214
  extend ::ActiveSupport::Autoload
211
215
  eager_autoload do
212
- autoload :FileResponse
213
216
  autoload :FileBody
214
217
  autoload :SendfileResponse
218
+ autoload :StreamResponse
215
219
  end
216
220
  end
217
221
  end
@@ -4,17 +4,6 @@ require 'spec_helper'
4
4
 
5
5
  describe Grape::Validations do
6
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
15
- end
16
- end
17
- end
18
7
  subject do
19
8
  Class.new(Grape::API) do
20
9
  params do
@@ -26,6 +15,25 @@ describe Grape::Validations do
26
15
  end
27
16
  end
28
17
 
18
+ let(:default_length_validator) do
19
+ Class.new(Grape::Validations::Validators::Base) do
20
+ def validate_param!(attr_name, params)
21
+ @option = params[:max].to_i if params.key?(:max)
22
+ return if params[attr_name].length <= @option
23
+
24
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long")
25
+ end
26
+ end
27
+ end
28
+
29
+ before do
30
+ described_class.register_validator('default_length', default_length_validator)
31
+ end
32
+
33
+ after do
34
+ described_class.deregister_validator('default_length')
35
+ end
36
+
29
37
  def app
30
38
  subject
31
39
  end
@@ -35,11 +43,13 @@ describe Grape::Validations do
35
43
  expect(last_response.status).to eq 200
36
44
  expect(last_response.body).to eq 'bacon'
37
45
  end
46
+
38
47
  it 'over 140 characters' do
39
48
  get '/', text: 'a' * 141
40
49
  expect(last_response.status).to eq 400
41
50
  expect(last_response.body).to eq 'text must be at the most 140 characters long'
42
51
  end
52
+
43
53
  it 'specified in the query string' do
44
54
  get '/', text: 'a' * 141, max: 141
45
55
  expect(last_response.status).to eq 200
@@ -48,15 +58,6 @@ describe Grape::Validations do
48
58
  end
49
59
 
50
60
  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
61
  subject do
61
62
  Class.new(Grape::API) do
62
63
  params do
@@ -68,6 +69,22 @@ describe Grape::Validations do
68
69
  end
69
70
  end
70
71
 
72
+ let(:in_body_validator) do
73
+ Class.new(Grape::Validations::Validators::PresenceValidator) do
74
+ def validate(request)
75
+ validate!(request.env['api.request.body'])
76
+ end
77
+ end
78
+ end
79
+
80
+ before do
81
+ described_class.register_validator('in_body', in_body_validator)
82
+ end
83
+
84
+ after do
85
+ described_class.deregister_validator('in_body')
86
+ end
87
+
71
88
  def app
72
89
  subject
73
90
  end
@@ -77,6 +94,7 @@ describe Grape::Validations do
77
94
  expect(last_response.status).to eq 200
78
95
  expect(last_response.body).to eq 'bacon'
79
96
  end
97
+
80
98
  it 'ignores field in query' do
81
99
  get '/', nil, text: 'abc'
82
100
  expect(last_response.status).to eq 400
@@ -85,15 +103,6 @@ describe Grape::Validations do
85
103
  end
86
104
 
87
105
  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
106
  subject do
98
107
  Class.new(Grape::API) do
99
108
  params do
@@ -105,6 +114,22 @@ describe Grape::Validations do
105
114
  end
106
115
  end
107
116
 
117
+ let(:message_key_validator) do
118
+ Class.new(Grape::Validations::Validators::PresenceValidator) do
119
+ def validate_param!(attr_name, _params)
120
+ raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: :presence)
121
+ end
122
+ end
123
+ end
124
+
125
+ before do
126
+ described_class.register_validator('with_message_key', message_key_validator)
127
+ end
128
+
129
+ after do
130
+ described_class.deregister_validator('with_message_key')
131
+ end
132
+
108
133
  def app
109
134
  subject
110
135
  end
@@ -117,22 +142,6 @@ describe Grape::Validations do
117
142
  end
118
143
 
119
144
  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
145
  subject do
137
146
  Class.new(Grape::API) do
138
147
  params do
@@ -146,6 +155,29 @@ describe Grape::Validations do
146
155
  end
147
156
  end
148
157
 
158
+ let(:admin_validator) do
159
+ Class.new(Grape::Validations::Validators::Base) do
160
+ def validate(request)
161
+ # return if the param we are checking was not in request
162
+ # @attrs is a list containing the attribute we are currently validating
163
+ return unless request.params.key? @attrs.first
164
+ # check if admin flag is set to true
165
+ return unless @option
166
+ # check if user is admin or not
167
+ # as an example get a token from request and check if it's admin or not
168
+ raise Grape::Exceptions::Validation.new(params: @attrs, message: 'Can not set Admin only field.') unless request.headers['X-Access-Token'] == 'admin'
169
+ end
170
+ end
171
+ end
172
+
173
+ before do
174
+ described_class.register_validator('admin', admin_validator)
175
+ end
176
+
177
+ after do
178
+ described_class.deregister_validator('admin')
179
+ end
180
+
149
181
  def app
150
182
  subject
151
183
  end
@@ -41,18 +41,18 @@ describe Grape::API do
41
41
 
42
42
  it 'works for unspecified format' do
43
43
  get '/users'
44
- expect(last_response.status).to eql 200
44
+ expect(last_response.status).to be 200
45
45
  expect(last_response.content_type).to eql 'application/json'
46
46
  end
47
47
 
48
48
  it 'works for specified format' do
49
49
  get '/users.json'
50
- expect(last_response.status).to eql 200
50
+ expect(last_response.status).to be 200
51
51
  expect(last_response.content_type).to eql 'application/json'
52
52
  end
53
53
 
54
54
  it "doesn't work for format different than specified" do
55
55
  get '/users.txt'
56
- expect(last_response.status).to eql 404
56
+ expect(last_response.status).to be 404
57
57
  end
58
58
  end
@@ -31,8 +31,9 @@ describe Grape::API::Instance do
31
31
 
32
32
  context 'Params endpoint type' do
33
33
  subject { DefinesBooleanInstanceSpec::API.new.router.map['POST'].first.options[:params]['message'][:type] }
34
+
34
35
  it 'params type is a boolean' do
35
- is_expected.to eq 'Grape::API::Boolean'
36
+ expect(subject).to eq 'Grape::API::Boolean'
36
37
  end
37
38
  end
38
39
  end