grape 1.6.1 → 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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +120 -19
  5. data/UPGRADING.md +19 -4
  6. data/lib/grape/api/instance.rb +1 -1
  7. data/lib/grape/dsl/api.rb +0 -2
  8. data/lib/grape/dsl/callbacks.rb +0 -2
  9. data/lib/grape/dsl/configuration.rb +0 -2
  10. data/lib/grape/dsl/desc.rb +0 -15
  11. data/lib/grape/dsl/helpers.rb +0 -2
  12. data/lib/grape/dsl/inside_route.rb +33 -29
  13. data/lib/grape/dsl/middleware.rb +0 -2
  14. data/lib/grape/dsl/parameters.rb +5 -7
  15. data/lib/grape/dsl/request_response.rb +0 -2
  16. data/lib/grape/dsl/routing.rb +4 -2
  17. data/lib/grape/dsl/settings.rb +0 -2
  18. data/lib/grape/dsl/validations.rb +0 -15
  19. data/lib/grape/error_formatter/json.rb +7 -1
  20. data/lib/grape/exceptions/base.rb +2 -2
  21. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  22. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  23. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  24. data/lib/grape/exceptions/validation.rb +0 -4
  25. data/lib/grape/locale/en.yml +9 -8
  26. data/lib/grape/middleware/auth/dsl.rb +0 -1
  27. data/lib/grape/middleware/error.rb +2 -2
  28. data/lib/grape/request.rb +2 -0
  29. data/lib/grape/validations/attributes_doc.rb +58 -0
  30. data/lib/grape/validations/params_scope.rb +66 -40
  31. data/lib/grape/validations/types/array_coercer.rb +2 -2
  32. data/lib/grape/validations/types/build_coercer.rb +94 -0
  33. data/lib/grape/validations/types/dry_type_coercer.rb +13 -8
  34. data/lib/grape/validations/types/json.rb +2 -0
  35. data/lib/grape/validations/types/primitive_coercer.rb +20 -10
  36. data/lib/grape/validations/types/set_coercer.rb +3 -2
  37. data/lib/grape/validations/types.rb +20 -26
  38. data/lib/grape/validations/validators/base.rb +7 -0
  39. data/lib/grape/validations.rb +16 -6
  40. data/lib/grape/version.rb +1 -1
  41. data/lib/grape.rb +20 -15
  42. data/spec/grape/api/custom_validations_spec.rb +41 -2
  43. data/spec/grape/api/deeply_included_options_spec.rb +0 -2
  44. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -2
  45. data/spec/grape/api/documentation_spec.rb +59 -0
  46. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  47. data/spec/grape/api/instance_spec.rb +0 -1
  48. data/spec/grape/api/invalid_format_spec.rb +0 -2
  49. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  50. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  51. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  52. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  53. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  54. data/spec/grape/api/recognize_path_spec.rb +0 -2
  55. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  56. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  57. data/spec/grape/api/routes_with_requirements_spec.rb +0 -2
  58. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -2
  59. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  60. data/spec/grape/api_remount_spec.rb +0 -1
  61. data/spec/grape/api_spec.rb +18 -5
  62. data/spec/grape/config_spec.rb +0 -2
  63. data/spec/grape/dsl/callbacks_spec.rb +0 -2
  64. data/spec/grape/dsl/configuration_spec.rb +0 -2
  65. data/spec/grape/dsl/desc_spec.rb +0 -2
  66. data/spec/grape/dsl/headers_spec.rb +2 -4
  67. data/spec/grape/dsl/helpers_spec.rb +0 -2
  68. data/spec/grape/dsl/inside_route_spec.rb +10 -12
  69. data/spec/grape/dsl/logger_spec.rb +0 -2
  70. data/spec/grape/dsl/middleware_spec.rb +0 -2
  71. data/spec/grape/dsl/parameters_spec.rb +0 -2
  72. data/spec/grape/dsl/request_response_spec.rb +6 -8
  73. data/spec/grape/dsl/routing_spec.rb +1 -3
  74. data/spec/grape/dsl/settings_spec.rb +0 -2
  75. data/spec/grape/dsl/validations_spec.rb +0 -17
  76. data/spec/grape/endpoint/declared_spec.rb +2 -4
  77. data/spec/grape/endpoint_spec.rb +22 -3
  78. data/spec/grape/entity_spec.rb +0 -1
  79. data/spec/grape/exceptions/base_spec.rb +16 -2
  80. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -2
  81. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -2
  82. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  83. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  84. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  85. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  86. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  87. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  88. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  89. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  90. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  91. data/spec/grape/exceptions/validation_errors_spec.rb +0 -1
  92. data/spec/grape/exceptions/validation_spec.rb +1 -3
  93. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -2
  94. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -2
  95. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -2
  96. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  97. data/spec/grape/integration/rack_sendfile_spec.rb +0 -2
  98. data/spec/grape/integration/rack_spec.rb +0 -2
  99. data/spec/grape/loading_spec.rb +0 -2
  100. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  101. data/spec/grape/middleware/auth/dsl_spec.rb +0 -2
  102. data/spec/grape/middleware/auth/strategies_spec.rb +0 -2
  103. data/spec/grape/middleware/base_spec.rb +0 -2
  104. data/spec/grape/middleware/error_spec.rb +6 -1
  105. data/spec/grape/middleware/exception_spec.rb +0 -2
  106. data/spec/grape/middleware/formatter_spec.rb +0 -2
  107. data/spec/grape/middleware/globals_spec.rb +0 -2
  108. data/spec/grape/middleware/stack_spec.rb +0 -2
  109. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -2
  110. data/spec/grape/middleware/versioner/header_spec.rb +18 -4
  111. data/spec/grape/middleware/versioner/param_spec.rb +0 -2
  112. data/spec/grape/middleware/versioner/path_spec.rb +0 -2
  113. data/spec/grape/middleware/versioner_spec.rb +0 -2
  114. data/spec/grape/named_api_spec.rb +0 -2
  115. data/spec/grape/parser_spec.rb +0 -2
  116. data/spec/grape/path_spec.rb +0 -2
  117. data/spec/grape/presenters/presenter_spec.rb +0 -2
  118. data/spec/grape/request_spec.rb +0 -2
  119. data/spec/grape/util/inheritable_setting_spec.rb +0 -1
  120. data/spec/grape/util/inheritable_values_spec.rb +0 -1
  121. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -1
  122. data/spec/grape/util/stackable_values_spec.rb +0 -1
  123. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  124. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  125. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  126. data/spec/grape/validations/instance_behaivour_spec.rb +0 -2
  127. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -2
  128. data/spec/grape/validations/params_scope_spec.rb +315 -86
  129. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -2
  130. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  131. data/spec/grape/validations/types/primitive_coercer_spec.rb +20 -5
  132. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  133. data/spec/grape/validations/types_spec.rb +28 -2
  134. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -2
  135. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -2
  136. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -2
  137. data/spec/grape/validations/validators/coerce_spec.rb +0 -2
  138. data/spec/grape/validations/validators/default_spec.rb +0 -2
  139. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -2
  140. data/spec/grape/validations/validators/except_values_spec.rb +0 -2
  141. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -2
  142. data/spec/grape/validations/validators/presence_spec.rb +0 -2
  143. data/spec/grape/validations/validators/regexp_spec.rb +0 -2
  144. data/spec/grape/validations/validators/same_as_spec.rb +0 -2
  145. data/spec/grape/validations/validators/values_spec.rb +0 -2
  146. data/spec/grape/validations_spec.rb +50 -22
  147. data/spec/integration/multi_json/json_spec.rb +0 -2
  148. data/spec/integration/multi_xml/xml_spec.rb +0 -2
  149. data/spec/spec_helper.rb +9 -4
  150. metadata +17 -8
  151. data/spec/support/eager_load.rb +0 -19
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'grape/validations/types/json'
4
+ require 'grape/validations/types/file'
5
+
3
6
  module Grape
4
7
  module Validations
5
8
  # Module for code related to grape's system for
@@ -13,7 +16,8 @@ module Grape
13
16
  # and {Grape::Dsl::Parameters#optional}. The main
14
17
  # entry point for this process is {Types.build_coercer}.
15
18
  module Types
16
- # Types representing a single value, which are coerced.
19
+ module_function
20
+
17
21
  PRIMITIVES = [
18
22
  # Numerical
19
23
  Integer,
@@ -35,33 +39,23 @@ module Grape
35
39
  ].freeze
36
40
 
37
41
  # Types representing data structures.
38
- STRUCTURES = [
39
- Hash,
40
- Array,
41
- Set
42
- ].freeze
42
+ STRUCTURES = [Hash, Array, Set].freeze
43
43
 
44
- # Special custom types provided by Grape.
45
44
  SPECIAL = {
46
- JSON => Json,
45
+ ::JSON => Json,
47
46
  Array[JSON] => JsonArray,
48
47
  ::File => File,
49
48
  Rack::Multipart::UploadedFile => File
50
49
  }.freeze
51
50
 
52
- GROUPS = [
53
- Array,
54
- Hash,
55
- JSON,
56
- Array[JSON]
57
- ].freeze
51
+ GROUPS = [Array, Hash, JSON, Array[JSON]].freeze
58
52
 
59
53
  # Is the given class a primitive type as recognized by Grape?
60
54
  #
61
55
  # @param type [Class] type to check
62
56
  # @return [Boolean] whether or not the type is known by Grape as a valid
63
57
  # type for a single value
64
- def self.primitive?(type)
58
+ def primitive?(type)
65
59
  PRIMITIVES.include?(type)
66
60
  end
67
61
 
@@ -71,7 +65,7 @@ module Grape
71
65
  # @param type [Class] type to check
72
66
  # @return [Boolean] whether or not the type is known by Grape as a valid
73
67
  # data structure type
74
- def self.structure?(type)
68
+ def structure?(type)
75
69
  STRUCTURES.include?(type)
76
70
  end
77
71
 
@@ -83,7 +77,7 @@ module Grape
83
77
  # @param type [Array<Class>,Set<Class>] type (or type list!) to check
84
78
  # @return [Boolean] +true+ if the given value will be treated as
85
79
  # a list of types.
86
- def self.multiple?(type)
80
+ def multiple?(type)
87
81
  (type.is_a?(Array) || type.is_a?(Set)) && type.size > 1
88
82
  end
89
83
 
@@ -94,7 +88,7 @@ module Grape
94
88
  #
95
89
  # @param type [Class] type to check
96
90
  # @return [Boolean] +true+ if special routines are available
97
- def self.special?(type)
91
+ def special?(type)
98
92
  SPECIAL.key? type
99
93
  end
100
94
 
@@ -103,7 +97,7 @@ module Grape
103
97
  #
104
98
  # @param type [Array<Class>,Class] type to check
105
99
  # @return [Boolean] +true+ if the type is a supported group type
106
- def self.group?(type)
100
+ def group?(type)
107
101
  GROUPS.include? type
108
102
  end
109
103
 
@@ -112,7 +106,7 @@ module Grape
112
106
  #
113
107
  # @param type [Class] type to check
114
108
  # @return [Boolean] whether or not the type can be used as a custom type
115
- def self.custom?(type)
109
+ def custom?(type)
116
110
  !primitive?(type) &&
117
111
  !structure?(type) &&
118
112
  !multiple?(type) &&
@@ -125,13 +119,13 @@ module Grape
125
119
  # @param type [Array<Class>,Class] type to check
126
120
  # @return [Boolean] true if +type+ is a collection of a type that implements
127
121
  # its own +#parse+ method.
128
- def self.collection_of_custom?(type)
122
+ def collection_of_custom?(type)
129
123
  (type.is_a?(Array) || type.is_a?(Set)) &&
130
124
  type.length == 1 &&
131
125
  (custom?(type.first) || special?(type.first))
132
126
  end
133
127
 
134
- def self.map_special(type)
128
+ def map_special(type)
135
129
  SPECIAL.fetch(type, type)
136
130
  end
137
131
 
@@ -163,13 +157,13 @@ module Grape
163
157
  # @param method [Class,#call] the coercion method to use
164
158
  # @return [Object] object to be used
165
159
  # for coercion and type validation
166
- def self.build_coercer(type, method: nil, strict: false)
160
+ def build_coercer(type, method: nil, strict: false)
167
161
  cache_instance(type, method, strict) do
168
162
  create_coercer_instance(type, method, strict)
169
163
  end
170
164
  end
171
165
 
172
- def self.create_coercer_instance(type, method, strict)
166
+ def create_coercer_instance(type, method, strict)
173
167
  # Maps a custom type provided by Grape, it doesn't map types wrapped by collections!!!
174
168
  type = Types.map_special(type)
175
169
 
@@ -193,7 +187,7 @@ module Grape
193
187
  end
194
188
  end
195
189
 
196
- def self.cache_instance(type, method, strict, &_block)
190
+ def cache_instance(type, method, strict, &_block)
197
191
  key = cache_key(type, method, strict)
198
192
 
199
193
  return @__cache[key] if @__cache.key?(key)
@@ -207,7 +201,7 @@ module Grape
207
201
  instance
208
202
  end
209
203
 
210
- def self.cache_key(type, method, strict)
204
+ def cache_key(type, method, strict)
211
205
  [type, method, strict].each_with_object(+'_') do |val, memo|
212
206
  next if val.nil?
213
207
 
@@ -93,3 +93,10 @@ module Grape
93
93
  end
94
94
  end
95
95
  end
96
+
97
+ Grape::Validations::Base = Class.new(Grape::Validations::Validators::Base) do
98
+ def initialize(*)
99
+ super
100
+ warn '[DEPRECATION] `Grape::Validations::Base` is deprecated. Use `Grape::Validations::Validators::Base` instead.'
101
+ end
102
+ 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.6.1'
5
+ VERSION = '1.7.0'
6
6
  end
data/lib/grape.rb CHANGED
@@ -7,19 +7,22 @@ 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'
10
12
  require 'active_support'
13
+ require 'active_support/concern'
11
14
  require 'active_support/version'
12
15
  require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR > 6
13
- require 'active_support/core_ext/hash/indifferent_access'
14
- require 'active_support/core_ext/object/blank'
15
16
  require 'active_support/core_ext/array/conversions'
16
17
  require 'active_support/core_ext/array/extract_options'
17
18
  require 'active_support/core_ext/array/wrap'
18
19
  require 'active_support/core_ext/hash/conversions'
19
20
  require 'active_support/core_ext/hash/deep_merge'
20
21
  require 'active_support/core_ext/hash/except'
22
+ require 'active_support/core_ext/hash/indifferent_access'
21
23
  require 'active_support/core_ext/hash/reverse_merge'
22
24
  require 'active_support/core_ext/hash/slice'
25
+ require 'active_support/core_ext/object/blank'
23
26
  require 'active_support/dependencies/autoload'
24
27
  require 'active_support/notifications'
25
28
  require 'i18n'
@@ -72,14 +75,17 @@ module Grape
72
75
  autoload :UnknownParameter
73
76
  autoload :InvalidWithOptionForRepresent
74
77
  autoload :IncompatibleOptionValues
75
- autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
76
- autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
78
+ autoload :MissingGroupType
79
+ autoload :UnsupportedGroupType
77
80
  autoload :InvalidMessageBody
78
81
  autoload :InvalidAcceptHeader
79
82
  autoload :InvalidVersionHeader
80
83
  autoload :MethodNotAllowed
81
84
  autoload :InvalidResponse
82
85
  autoload :EmptyMessageBody
86
+ autoload :TooManyMultipartFiles
87
+ autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
88
+ autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
83
89
  end
84
90
  end
85
91
 
@@ -223,13 +229,21 @@ module Grape
223
229
  module Validations
224
230
  extend ::ActiveSupport::Autoload
225
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
+
226
242
  module Types
227
243
  extend ::ActiveSupport::Autoload
228
244
 
229
245
  eager_autoload do
230
246
  autoload :InvalidValue
231
- autoload :File
232
- autoload :Json
233
247
  autoload :DryTypeCoercer
234
248
  autoload :ArrayCoercer
235
249
  autoload :SetCoercer
@@ -241,15 +255,6 @@ module Grape
241
255
  end
242
256
  end
243
257
 
244
- eager_autoload do
245
- autoload :AttributesIterator
246
- autoload :MultipleAttributesIterator
247
- autoload :SingleAttributeIterator
248
- autoload :ParamsScope
249
- autoload :Types
250
- autoload :ValidatorFactory
251
- end
252
-
253
258
  module Validators
254
259
  extend ::ActiveSupport::Autoload
255
260
 
@@ -1,8 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Validations do
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
19
+ end
20
+ end
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
+
6
45
  context 'using a custom length validator' do
7
46
  subject do
8
47
  Class.new(Grape::API) do
@@ -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
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API::Instance do
6
4
  describe 'boolean constant' do
7
5
  module DefinesBooleanInstanceSpec
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Grape::API do
6
+ subject { Class.new(described_class) }
7
+
8
+ let(:app) { subject }
9
+
10
+ context 'an endpoint with documentation' do
11
+ it 'documents parameters' do
12
+ subject.params do
13
+ requires 'price', type: Float, desc: 'Sales price'
14
+ end
15
+ subject.get '/'
16
+
17
+ expect(subject.routes.first.params['price']).to eq(required: true,
18
+ type: 'Float',
19
+ desc: 'Sales price')
20
+ end
21
+
22
+ it 'allows documentation with a hash' do
23
+ documentation = { example: 'Joe' }
24
+
25
+ subject.params do
26
+ requires 'first_name', documentation: documentation
27
+ end
28
+ subject.get '/'
29
+
30
+ expect(subject.routes.first.params['first_name'][:documentation]).to eq(documentation)
31
+ end
32
+ end
33
+
34
+ context 'an endpoint without documentation' do
35
+ before do
36
+ subject.do_not_document!
37
+
38
+ subject.params do
39
+ requires :city, type: String, desc: 'Should be ignored'
40
+ optional :postal_code, type: Integer
41
+ end
42
+ subject.post '/' do
43
+ declared(params).to_json
44
+ end
45
+ end
46
+
47
+ it 'does not document parameters for the endpoint' do
48
+ expect(subject.routes.first.params).to eq({})
49
+ end
50
+
51
+ it 'still declares params internally' do
52
+ data = { city: 'Berlin', postal_code: 10_115 }
53
+
54
+ post '/', data
55
+
56
+ expect(last_response.body).to eq(data.to_json)
57
+ end
58
+ end
59
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API::Helpers do
6
4
  let(:user) { 'Miguel Caneo' }
7
5
  let(:id) { '42' }
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
3
  require 'shared/versioning_examples'
5
4
 
6
5
  describe Grape::API::Instance do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API::Helpers do
6
4
  module NestedHelpersSpec
7
5
  module HelperMethods
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API::Helpers do
6
4
  module PatchHelpersSpec
7
5
  class PatchPublic < Grape::API
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API do
6
4
  describe '.recognize_path' do
7
5
  subject { Class.new(described_class) }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API::Helpers do
6
4
  let(:app) do
7
5
  Class.new(Grape::API) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::API::Helpers do
6
4
  subject do
7
5
  shared_params = Module.new do
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
3
  require 'shared/versioning_examples'
5
4
 
6
5
  describe Grape::API do
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
3
  require 'shared/versioning_examples'
5
4
 
6
5
  describe Grape::API do
@@ -1217,7 +1216,7 @@ describe Grape::API do
1217
1216
 
1218
1217
  it 'does not set Cache-Control' do
1219
1218
  get '/foo'
1220
- expect(last_response.headers['Cache-Control']).to eq(nil)
1219
+ expect(last_response.headers['Cache-Control']).to be_nil
1221
1220
  end
1222
1221
 
1223
1222
  it 'sets content type for xml' do
@@ -1242,7 +1241,7 @@ describe Grape::API do
1242
1241
 
1243
1242
  it 'returns raw data when content type binary' do
1244
1243
  image_filename = 'grape.png'
1245
- file = File.open(image_filename, 'rb', &:read)
1244
+ file = File.binread(image_filename)
1246
1245
  subject.format :binary
1247
1246
  subject.get('/binary_file') { File.binread(image_filename) }
1248
1247
  get '/binary_file'
@@ -1274,7 +1273,7 @@ describe Grape::API do
1274
1273
  get '/stream', {}, 'HTTP_VERSION' => 'HTTP/1.1', 'SERVER_PROTOCOL' => 'HTTP/1.1'
1275
1274
 
1276
1275
  expect(last_response.headers['Content-Type']).to eq('text/plain')
1277
- expect(last_response.headers['Content-Length']).to eq(nil)
1276
+ expect(last_response.headers['Content-Length']).to be_nil
1278
1277
  expect(last_response.headers['Cache-Control']).to eq('no-cache')
1279
1278
  expect(last_response.headers['Transfer-Encoding']).to eq('chunked')
1280
1279
 
@@ -2292,7 +2291,7 @@ describe Grape::API do
2292
2291
  subject.rescue_from :all, with: :not_exist_method
2293
2292
  subject.get('/rescue_method') { raise StandardError }
2294
2293
 
2295
- expect { get '/rescue_method' }.to raise_error(NoMethodError, /^undefined method `not_exist_method'/)
2294
+ expect { get '/rescue_method' }.to raise_error(NoMethodError, /^undefined method 'not_exist_method'/)
2296
2295
  end
2297
2296
 
2298
2297
  it 'correctly chooses exception handler if :all handler is specified' do
@@ -4158,6 +4157,20 @@ describe Grape::API do
4158
4157
  end
4159
4158
  end
4160
4159
 
4160
+ context 'with non-UTF-8 characters in specified format' do
4161
+ it 'converts the characters' do
4162
+ subject.format :json
4163
+ subject.content_type :json, 'application/json'
4164
+ subject.get '/something' do
4165
+ 'foo'
4166
+ end
4167
+ get '/something?format=%0A%0B%BF'
4168
+ expect(last_response.status).to eq(406)
4169
+ message = "The requested format '\n\u000b\357\277\275' is not supported."
4170
+ expect(last_response.body).to eq({ error: message }.to_json)
4171
+ end
4172
+ end
4173
+
4161
4174
  context 'body' do
4162
4175
  context 'false' do
4163
4176
  before do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe '.configure' do
6
4
  before do
7
5
  Grape.configure do |config|
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module CallbacksSpec
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module ConfigurationSpec
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module DescSpec
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module HeadersSpec
@@ -54,8 +52,8 @@ module Grape
54
52
  context 'when no headers are set' do
55
53
  describe '#header' do
56
54
  it 'returns nil' do
57
- expect(subject.header['First Key']).to be nil
58
- expect(subject.header('First Key')).to be nil
55
+ expect(subject.header['First Key']).to be_nil
56
+ expect(subject.header('First Key')).to be_nil
59
57
  end
60
58
  end
61
59
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module HelpersSpec