grape 3.3.4 → 4.0.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -0
  3. data/CONTRIBUTING.md +16 -0
  4. data/README.md +208 -8
  5. data/UPGRADING.md +756 -6
  6. data/lib/grape/api/instance.rb +40 -33
  7. data/lib/grape/content_types.rb +47 -1
  8. data/lib/grape/dry_types.rb +1 -1
  9. data/lib/grape/dsl/callbacks.rb +3 -9
  10. data/lib/grape/dsl/declared.rb +4 -4
  11. data/lib/grape/dsl/desc.rb +18 -8
  12. data/lib/grape/dsl/entity.rb +37 -19
  13. data/lib/grape/dsl/helpers.rb +3 -3
  14. data/lib/grape/dsl/inside_route.rb +20 -8
  15. data/lib/grape/dsl/middleware.rb +3 -3
  16. data/lib/grape/dsl/parameters.rb +54 -28
  17. data/lib/grape/dsl/request_response.rb +37 -39
  18. data/lib/grape/dsl/rescue_options.rb +6 -5
  19. data/lib/grape/dsl/routing.rb +116 -49
  20. data/lib/grape/dsl/settings.rb +1 -1
  21. data/lib/grape/dsl/validations.rb +3 -3
  22. data/lib/grape/dsl/version_options.rb +3 -3
  23. data/lib/grape/endpoint/options.rb +13 -7
  24. data/lib/grape/endpoint.rb +141 -118
  25. data/lib/grape/env.rb +7 -0
  26. data/lib/grape/error_formatter/base.rb +6 -5
  27. data/lib/grape/error_formatter.rb +6 -2
  28. data/lib/grape/exceptions/error_response.rb +4 -1
  29. data/lib/grape/exceptions/unknown_error_formatter.rb +11 -0
  30. data/lib/grape/exceptions/validation.rb +9 -8
  31. data/lib/grape/formatter/json.rb +1 -0
  32. data/lib/grape/formatter/serializable_hash.rb +1 -0
  33. data/lib/grape/locale/en.yml +1 -0
  34. data/lib/grape/middleware/auth/dsl.rb +5 -33
  35. data/lib/grape/middleware/error.rb +153 -46
  36. data/lib/grape/middleware/formatter.rb +95 -26
  37. data/lib/grape/middleware/precomputed_content_types.rb +12 -7
  38. data/lib/grape/middleware/stack.rb +13 -4
  39. data/lib/grape/middleware/versioner/base.rb +3 -9
  40. data/lib/grape/middleware/versioner/path.rb +49 -7
  41. data/lib/grape/namespace.rb +3 -2
  42. data/lib/grape/path.rb +8 -69
  43. data/lib/grape/precompiled_json.rb +50 -0
  44. data/lib/grape/request.rb +36 -4
  45. data/lib/grape/router/base_route.rb +47 -10
  46. data/lib/grape/router/greedy_route.rb +5 -1
  47. data/lib/grape/router/pattern/path.rb +78 -0
  48. data/lib/grape/router/pattern.rb +60 -14
  49. data/lib/grape/router/route.rb +62 -10
  50. data/lib/grape/router.rb +100 -57
  51. data/lib/grape/serve_stream/file_body.rb +6 -0
  52. data/lib/grape/serve_stream/stream_response.rb +6 -0
  53. data/lib/grape/util/api_description.rb +10 -1
  54. data/lib/grape/util/cache.rb +21 -2
  55. data/lib/grape/util/deep_freeze.rb +1 -2
  56. data/lib/grape/util/freeze_on_new.rb +20 -0
  57. data/lib/grape/util/inheritable_setting.rb +751 -37
  58. data/lib/grape/util/media_type.rb +10 -3
  59. data/lib/grape/util/path_normalizer.rb +12 -9
  60. data/lib/grape/util/registry.rb +12 -2
  61. data/lib/grape/util/shadowed_rescue_handlers.rb +49 -0
  62. data/lib/grape/util/stackable_values.rb +32 -6
  63. data/lib/grape/validations/attributes_iterator.rb +21 -4
  64. data/lib/grape/validations/contract_scope.rb +8 -7
  65. data/lib/grape/validations/oneof_collector.rb +6 -10
  66. data/lib/grape/validations/params_documentation.rb +2 -2
  67. data/lib/grape/validations/params_scope.rb +66 -26
  68. data/lib/grape/validations/single_attribute_iterator.rb +5 -3
  69. data/lib/grape/validations/types/array_coercer.rb +4 -6
  70. data/lib/grape/validations/types/custom_type_coercer.rb +7 -1
  71. data/lib/grape/validations/types/dry_type_coercer.rb +3 -1
  72. data/lib/grape/validations/types/json.rb +1 -3
  73. data/lib/grape/validations/types/multiple_type_coercer.rb +5 -3
  74. data/lib/grape/validations/types/primitive_coercer.rb +12 -9
  75. data/lib/grape/validations/types/variant_collection_coercer.rb +8 -3
  76. data/lib/grape/validations/types.rb +5 -5
  77. data/lib/grape/validations/validations_spec.rb +14 -4
  78. data/lib/grape/validations/validators/base.rb +4 -7
  79. data/lib/grape/validations/validators/coerce_validator.rb +8 -2
  80. data/lib/grape/validations/validators/contract_scope_validator.rb +2 -1
  81. data/lib/grape/validations/validators/length_validator.rb +4 -2
  82. data/lib/grape/validations/validators/oneof_validator.rb +2 -0
  83. data/lib/grape/validations/validators/same_as_validator.rb +1 -0
  84. data/lib/grape/version.rb +2 -1
  85. data/lib/grape.rb +23 -2
  86. metadata +10 -9
  87. data/lib/grape/middleware/deprecated_options_hash_access.rb +0 -19
  88. data/lib/grape/util/base_inheritable.rb +0 -43
  89. data/lib/grape/util/inheritable_values.rb +0 -33
  90. data/lib/grape/util/reverse_stackable_values.rb +0 -15
@@ -7,10 +7,18 @@ module Grape
7
7
  # initialization. When +strict+ is true, it doesn't coerce a value but check
8
8
  # that it has the proper type.
9
9
  class PrimitiveCoercer < DryTypeCoercer
10
+ # The input classes Virtus refused for a given declared type, keyed by
11
+ # that type. Resolved once in #initialize rather than re-derived from
12
+ # +type+ on every value: the answer only ever depends on the
13
+ # declaration, and every coerced attribute of every request asks.
14
+ REJECTED_INPUTS = { String => [Array, Hash].freeze, Hash => [String].freeze }.freeze
15
+
10
16
  def initialize(type, strict: false)
11
17
  super
12
18
 
13
19
  @coercer = cache_coercer[type]
20
+ @rejected_inputs = REJECTED_INPUTS[type]
21
+ @treat_empty_as_nil = type != String
14
22
  end
15
23
 
16
24
  def call(val)
@@ -29,21 +37,16 @@ module Grape
29
37
  # but Virtus wouldn't accept it. So, this method only exists to not introduce
30
38
  # breaking changes.
31
39
  def reject?(val)
32
- case val
33
- when Array, Hash
34
- type == String
35
- when String
36
- type == Hash
37
- else
38
- false
39
- end
40
+ return false unless @rejected_inputs
41
+
42
+ @rejected_inputs.any? { |klass| val.is_a?(klass) }
40
43
  end
41
44
 
42
45
  # Dry-Types treats an empty string as invalid. However, Grape considers an empty string as
43
46
  # absence of a value and coerces it into nil. See a discussion there
44
47
  # https://github.com/ruby-grape/grape/pull/2045
45
48
  def treat_as_nil?(val)
46
- val == '' && type != String
49
+ @treat_empty_as_nil && val == ''
47
50
  end
48
51
  end
49
52
  end
@@ -6,6 +6,11 @@ module Grape
6
6
  # This class wraps {MultipleTypeCoercer}, for use with collections
7
7
  # that allow members of more than one type.
8
8
  class VariantCollectionCoercer
9
+ extend Grape::Util::FreezeOnNew
10
+
11
+ # @return [Array<Class>,Set<Class>] the member types as declared in the DSL
12
+ attr_reader :types
13
+
9
14
  # Construct a new coercer that will attempt to coerce
10
15
  # a list of values such that all members are of one of
11
16
  # the given types. The container may also optionally be
@@ -43,15 +48,15 @@ module Grape
43
48
  def call(value)
44
49
  return unless value.is_a? Array
45
50
 
46
- value =
51
+ coerced =
47
52
  if @method
48
53
  @method.call(value)
49
54
  else
50
55
  value.map { |v| @member_coercer.call(v) }
51
56
  end
52
- return Set.new value if @types.is_a? Set
57
+ return Set.new coerced if @types.is_a? Set
53
58
 
54
- value
59
+ coerced
55
60
  end
56
61
  end
57
62
  end
@@ -162,20 +162,20 @@ module Grape
162
162
 
163
163
  def create_coercer_instance(type, method, strict)
164
164
  # map_special doesn't recurse into collections — applied only to the top-level type here.
165
- type = map_special(type)
165
+ mapped = map_special(type)
166
166
 
167
167
  # Multiply-typed parameters, e.g. types: [Integer, String].
168
- return MultipleTypeCoercer.new(type, method) if multiple?(type)
168
+ return MultipleTypeCoercer.new(mapped, method) if multiple?(mapped)
169
169
 
170
170
  # User-supplied coercion method, or a custom type with its own #parse.
171
- return CustomTypeCoercer.new(type, method) if method || custom?(type)
171
+ return CustomTypeCoercer.new(mapped, method) if method || custom?(mapped)
172
172
 
173
173
  # Array/Set of a custom type — CustomTypeCoercer already handles single
174
174
  # custom types when an explicit coercion method is supplied.
175
- return CustomTypeCollectionCoercer.new(map_special(type.first), set: type.is_a?(Set)) if collection_of_custom?(type)
175
+ return CustomTypeCollectionCoercer.new(map_special(mapped.first), set: mapped.is_a?(Set)) if collection_of_custom?(mapped)
176
176
 
177
177
  # Fallback: let dry-types handle primitives, structures, and known specials.
178
- DryTypeCoercer.coercer_instance_for(type, strict:)
178
+ DryTypeCoercer.coercer_instance_for(mapped, strict:)
179
179
  end
180
180
 
181
181
  class CoercerCache < Grape::Util::Cache
@@ -51,7 +51,7 @@ module Grape
51
51
  @allow_blank = resolve_value(raw[:allow_blank])
52
52
  @fail_fast = raw[:fail_fast] || false
53
53
 
54
- @guessed_coerce_type = guess_coerce_type(@coerce_type, @values, @except_values)
54
+ @guessed_coerce_type = guess_coerce_type(declared_coerce_type, @values, @except_values)
55
55
  @shared_opts = { allow_blank: @allow_blank, fail_fast: @fail_fast }.freeze
56
56
  @validator_entries = build_validator_entries(raw)
57
57
 
@@ -97,13 +97,13 @@ module Grape
97
97
  def validate_value_coercion(coerce_type, *values_list)
98
98
  return unless coerce_type
99
99
 
100
- coerce_type = coerce_type.first if coerce_type.is_a?(Enumerable)
100
+ element_type = coerce_type.is_a?(Enumerable) ? coerce_type.first : coerce_type
101
101
  values_list.each do |values|
102
102
  next if !values || values.is_a?(Proc)
103
103
 
104
104
  value_types = values.is_a?(Range) ? [values.begin, values.end].compact : values
105
- value_types = value_types.map { |type| Grape::API::Boolean.build(type) } if coerce_type == Grape::API::Boolean
106
- raise Grape::Exceptions::IncompatibleOptionValues.new(:type, coerce_type, :values, values) unless value_types.all?(coerce_type)
105
+ value_types = value_types.map { |type| Grape::API::Boolean.build(type) } if element_type == Grape::API::Boolean
106
+ raise Grape::Exceptions::IncompatibleOptionValues.new(:type, element_type, :values, values) unless value_types.all?(element_type)
107
107
  end
108
108
  end
109
109
 
@@ -140,6 +140,16 @@ module Grape
140
140
  opt.is_a?(Hash) ? opt[:value] : opt
141
141
  end
142
142
 
143
+ # The type as written in the DSL. Identical to +@coerce_type+ except for
144
+ # a multiple-type declaration (+type: [Integer, String]+), where
145
+ # {#parse_coerce} wraps the declared list in a
146
+ # {Types::VariantCollectionCoercer} for runtime coercion — the
147
+ # definition-time coherence checks need the list back, since the wrapper
148
+ # matches nothing under +===+.
149
+ def declared_coerce_type
150
+ @coerce_type.is_a?(Types::VariantCollectionCoercer) ? @coerce_type.types : @coerce_type
151
+ end
152
+
143
153
  def guess_coerce_type(coerce_type, *values_list)
144
154
  return coerce_type unless coerce_type == Array
145
155
 
@@ -13,6 +13,7 @@ module Grape
13
13
  # (e.g. +memoize+, <tt>||=</tt>) will raise +FrozenError+ at request time.
14
14
  class Base
15
15
  extend Forwardable
16
+ extend Grape::Util::FreezeOnNew
16
17
  include Grape::Util::Translation
17
18
 
18
19
  attr_reader :attrs
@@ -45,10 +46,6 @@ module Grape
45
46
  end
46
47
  end
47
48
 
48
- def new(...)
49
- super.freeze
50
- end
51
-
52
49
  def inherited(klass)
53
50
  super
54
51
  Validations.register(klass)
@@ -67,7 +64,6 @@ module Grape
67
64
  def initialize(attrs, options, required, scope, opts)
68
65
  @attrs = Array(attrs).freeze
69
66
  @options = Grape::Util::DeepFreeze.deep_freeze(options)
70
- @option = @options # TODO: remove in next major release
71
67
  @required = required
72
68
  @scope = scope
73
69
  @opts = SharedOptions.new(**opts.slice(:allow_blank, :fail_fast))
@@ -81,9 +77,10 @@ module Grape
81
77
  # @raise [Grape::Exceptions::Validation] if validation failed
82
78
  # @return [void]
83
79
  def validate(request)
84
- return unless scope.should_validate?(request.params)
80
+ params = request.params
81
+ return unless scope.should_validate?(params)
85
82
 
86
- validate!(request.params)
83
+ validate!(params)
87
84
  end
88
85
 
89
86
  # Validates a given parameter hash.
@@ -21,10 +21,16 @@ module Grape
21
21
  end
22
22
  end
23
23
 
24
+ # The attribute is read once and held: +coerce_value+ only ever sees the
25
+ # value, never the Hash, so the two further reads the identity check
26
+ # used to make came back with the same object -- through a
27
+ # HashWithIndifferentAccess key conversion each time, for every coerced
28
+ # attribute of every request.
24
29
  def validate_param!(attr_name, params)
25
30
  validation_error!(attr_name) unless hash_like?(params)
26
31
 
27
- new_value = coerce_value(params[attr_name])
32
+ value = params[attr_name]
33
+ new_value = coerce_value(value)
28
34
 
29
35
  validation_error!(attr_name, new_value.message || exception_message) if new_value.is_a?(Types::InvalidValue)
30
36
 
@@ -37,7 +43,7 @@ module Grape
37
43
  # h[:list] = list
38
44
  # h
39
45
  # => #<Hashie::Mash list=[1, 2, 3, 4]>
40
- return if params[attr_name].instance_of?(new_value.class) && params[attr_name] == new_value
46
+ return if value.instance_of?(new_value.class) && value == new_value
41
47
 
42
48
  params[attr_name] = new_value
43
49
  end
@@ -4,11 +4,12 @@ module Grape
4
4
  module Validations
5
5
  module Validators
6
6
  class ContractScopeValidator
7
+ extend Grape::Util::FreezeOnNew
8
+
7
9
  attr_reader :schema
8
10
 
9
11
  def initialize(schema:)
10
12
  @schema = schema
11
- freeze
12
13
  end
13
14
 
14
15
  # Validates a given request.
@@ -10,7 +10,7 @@ module Grape
10
10
  @min, @max, @is = options.values_at(:min, :max, :is)
11
11
  validate_boundary!(:min, @min)
12
12
  validate_boundary!(:max, @max)
13
- raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if @min && @max && @min > @max
13
+ raise ArgumentError, "min `#{@min}` cannot be greater than max `#{@max}`" if @min && @max && @min > @max
14
14
 
15
15
  return if @is.nil?
16
16
  raise ArgumentError, 'is must be an integer greater than zero' unless @is.is_a?(Integer) && @is.positive?
@@ -18,6 +18,8 @@ module Grape
18
18
  end
19
19
 
20
20
  def validate_param!(attr_name, params)
21
+ return unless hash_like?(params)
22
+
21
23
  param = params[attr_name]
22
24
 
23
25
  return unless param.respond_to?(:length)
@@ -40,7 +42,7 @@ module Grape
40
42
  private
41
43
 
42
44
  def validate_boundary!(name, val)
43
- raise ArgumentError, "#{name} must be an integer greater than or equal to zero" if !val.nil? && (!val.is_a?(Integer) || val.negative?)
45
+ raise ArgumentError, "`#{name}` must be an integer greater than or equal to zero" if !val.nil? && (!val.is_a?(Integer) || val.negative?)
44
46
  end
45
47
  end
46
48
  end
@@ -18,6 +18,8 @@ module Grape
18
18
  end
19
19
 
20
20
  def validate_param!(attr_name, params)
21
+ return unless hash_like?(params)
22
+
21
23
  value = params[attr_name]
22
24
  return if value.nil? && !required?
23
25
 
@@ -10,6 +10,7 @@ module Grape
10
10
  end
11
11
 
12
12
  def validate_param!(attr_name, params)
13
+ return unless hash_like?(params)
13
14
  return if params[attr_name] == params[@value]
14
15
 
15
16
  validation_error!(attr_name, message { translate(:same_as, parameter: @value) })
data/lib/grape/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grape
4
- VERSION = '3.3.4'
4
+ # The current version of Grape.
5
+ VERSION = '4.0.0'
5
6
  end
data/lib/grape.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'logger'
4
+ require 'monitor'
4
5
  require 'active_support'
5
6
  require 'active_support/isolated_execution_state'
6
7
  require 'active_support/core_ext/array/conversions' # to_xml
@@ -41,7 +42,12 @@ loader.inflector.inflect(
41
42
  'dsl' => 'DSL'
42
43
  )
43
44
  railtie = "#{__dir__}/grape/railtie.rb"
44
- loader.do_not_eager_load(railtie)
45
+ # Grape::Testing is a test-environment helper -- it extends Grape::Endpoint with
46
+ # `before_each` and prepends a hook to Grape::Endpoint#run. It is documented as
47
+ # opt-in (`require 'grape/testing'`), which eager loading quietly contradicted
48
+ # by installing it in every process.
49
+ testing = "#{__dir__}/grape/testing.rb"
50
+ loader.do_not_eager_load(railtie, testing)
45
51
  loader.setup
46
52
 
47
53
  I18n.load_path << File.expand_path('grape/locale/en.yml', __dir__)
@@ -52,9 +58,17 @@ module Grape
52
58
  setting :param_builder, default: :hash_with_indifferent_access
53
59
  setting :lint, default: false
54
60
  setting :warn_on_helper_overrides, default: false
61
+ # Let an error response that cannot be rendered propagate out of the
62
+ # middleware stack instead of being answered with a failsafe 500.
63
+ setting :raise_rendering_errors, default: false
64
+
65
+ # The HTTP QUERY method (RFC 10008): a safe, idempotent request whose content
66
+ # carries the query. Rack has no constant for it yet, hence the literal.
67
+ QUERY = 'QUERY'
55
68
 
56
69
  HTTP_SUPPORTED_METHODS = [
57
70
  Rack::GET,
71
+ QUERY,
58
72
  Rack::POST,
59
73
  Rack::PUT,
60
74
  Rack::PATCH,
@@ -81,8 +95,15 @@ module Grape
81
95
  ]
82
96
  end.freeze
83
97
 
98
+ # The deprecation horizon is the version a deprecation announces as its
99
+ # removal point, so it is the *next* major rather than the current one, and
100
+ # it is derived from VERSION rather than written out. Written out, it went
101
+ # stale: it said '2.0' from 2023 (#2353) through all of 2.x, 3.x and 4.x, so
102
+ # a method deprecated through this deprecator announced a removal version
103
+ # that had already shipped, and every custom `behavior` lambda -- how a Rails
104
+ # app consumes deprecations -- was handed the same wrong number.
84
105
  def self.deprecator
85
- @deprecator ||= ActiveSupport::Deprecation.new('2.0', 'Grape')
106
+ @deprecator ||= ActiveSupport::Deprecation.new("#{Gem::Version.new(VERSION).segments.first + 1}.0", 'Grape')
86
107
  end
87
108
  end
88
109
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.4
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -156,6 +156,7 @@ files:
156
156
  - lib/grape/exceptions/missing_vendor_option.rb
157
157
  - lib/grape/exceptions/request_error.rb
158
158
  - lib/grape/exceptions/unknown_auth_strategy.rb
159
+ - lib/grape/exceptions/unknown_error_formatter.rb
159
160
  - lib/grape/exceptions/unknown_parameter.rb
160
161
  - lib/grape/exceptions/unknown_params_builder.rb
161
162
  - lib/grape/exceptions/unknown_validator.rb
@@ -176,7 +177,6 @@ files:
176
177
  - lib/grape/middleware/auth/strategies.rb
177
178
  - lib/grape/middleware/auth/strategy_info.rb
178
179
  - lib/grape/middleware/base.rb
179
- - lib/grape/middleware/deprecated_options_hash_access.rb
180
180
  - lib/grape/middleware/error.rb
181
181
  - lib/grape/middleware/filter.rb
182
182
  - lib/grape/middleware/formatter.rb
@@ -200,6 +200,7 @@ files:
200
200
  - lib/grape/parser/json.rb
201
201
  - lib/grape/parser/xml.rb
202
202
  - lib/grape/path.rb
203
+ - lib/grape/precompiled_json.rb
203
204
  - lib/grape/presenters/presenter.rb
204
205
  - lib/grape/railtie.rb
205
206
  - lib/grape/request.rb
@@ -208,19 +209,19 @@ files:
208
209
  - lib/grape/router/greedy_route.rb
209
210
  - lib/grape/router/mustermann_pattern.rb
210
211
  - lib/grape/router/pattern.rb
212
+ - lib/grape/router/pattern/path.rb
211
213
  - lib/grape/router/route.rb
212
214
  - lib/grape/serve_stream/file_body.rb
213
215
  - lib/grape/serve_stream/sendfile_response.rb
214
216
  - lib/grape/serve_stream/stream_response.rb
215
217
  - lib/grape/testing.rb
216
218
  - lib/grape/util/api_description.rb
217
- - lib/grape/util/base_inheritable.rb
218
219
  - lib/grape/util/cache.rb
219
220
  - lib/grape/util/deep_freeze.rb
220
221
  - lib/grape/util/endpoint_configuration.rb
222
+ - lib/grape/util/freeze_on_new.rb
221
223
  - lib/grape/util/header.rb
222
224
  - lib/grape/util/inheritable_setting.rb
223
- - lib/grape/util/inheritable_values.rb
224
225
  - lib/grape/util/lazy/base.rb
225
226
  - lib/grape/util/lazy/block.rb
226
227
  - lib/grape/util/lazy/value.rb
@@ -230,7 +231,7 @@ files:
230
231
  - lib/grape/util/media_type.rb
231
232
  - lib/grape/util/path_normalizer.rb
232
233
  - lib/grape/util/registry.rb
233
- - lib/grape/util/reverse_stackable_values.rb
234
+ - lib/grape/util/shadowed_rescue_handlers.rb
234
235
  - lib/grape/util/stackable_values.rb
235
236
  - lib/grape/util/translation.rb
236
237
  - lib/grape/validations.rb
@@ -282,9 +283,9 @@ licenses:
282
283
  - MIT
283
284
  metadata:
284
285
  bug_tracker_uri: https://github.com/ruby-grape/grape/issues
285
- changelog_uri: https://github.com/ruby-grape/grape/blob/v3.3.4/CHANGELOG.md
286
- documentation_uri: https://www.rubydoc.info/gems/grape/3.3.4
287
- source_code_uri: https://github.com/ruby-grape/grape/tree/v3.3.4
286
+ changelog_uri: https://github.com/ruby-grape/grape/blob/v4.0.0/CHANGELOG.md
287
+ documentation_uri: https://www.rubydoc.info/gems/grape/4.0.0
288
+ source_code_uri: https://github.com/ruby-grape/grape/tree/v4.0.0
288
289
  rubygems_mfa_required: 'true'
289
290
  rdoc_options: []
290
291
  require_paths:
@@ -300,7 +301,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
300
301
  - !ruby/object:Gem::Version
301
302
  version: '0'
302
303
  requirements: []
303
- rubygems_version: 4.0.14
304
+ rubygems_version: 4.0.16
304
305
  specification_version: 4
305
306
  summary: A simple Ruby framework for building REST-like APIs.
306
307
  test_files: []
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Middleware
5
- # Mixin for per-middleware +Options+ +Data+ classes that need to keep
6
- # accepting legacy +data[:key]+ Hash-style access while nudging callers
7
- # toward the named accessor. Emits a +Grape.deprecator+ warning then
8
- # forwards to +public_send(key)+.
9
- module DeprecatedOptionsHashAccess
10
- def [](key)
11
- Grape.deprecator.warn(
12
- "`#{self.class.name}#[]` is deprecated. " \
13
- "Use the named accessor `#{key}` instead."
14
- )
15
- public_send(key) if members.include?(key)
16
- end
17
- end
18
- end
19
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Util
5
- # Base for classes which need to operate with own values kept
6
- # in the hash and inherited values kept in a Hash-like object.
7
- #
8
- # +@new_values+ is lazily allocated on first write so settings layers
9
- # that only inherit (never override) don't carry an empty Hash each.
10
- class BaseInheritable
11
- attr_accessor :inherited_values, :new_values
12
-
13
- # @param inherited_values [Object] An object implementing an interface
14
- # of the Hash class.
15
- def initialize(inherited_values = nil)
16
- @inherited_values = inherited_values || {}
17
- # @new_values stays nil until the first write.
18
- end
19
-
20
- def delete(*keys)
21
- return [] unless @new_values
22
-
23
- keys.map { |key| @new_values.delete(key) }
24
- end
25
-
26
- def initialize_copy(other)
27
- super
28
- @inherited_values = other.inherited_values
29
- @new_values = other.new_values&.dup
30
- end
31
-
32
- def keys
33
- return @inherited_values.keys if @new_values.nil? || @new_values.empty?
34
-
35
- (@inherited_values.keys + @new_values.keys).uniq
36
- end
37
-
38
- def key?(name)
39
- @inherited_values.key?(name) || @new_values&.key?(name) || false
40
- end
41
- end
42
- end
43
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Util
5
- class InheritableValues < BaseInheritable
6
- def [](name)
7
- return @inherited_values[name] unless @new_values
8
-
9
- @new_values.fetch(name) { @inherited_values[name] }
10
- end
11
-
12
- def []=(name, value)
13
- (@new_values ||= {})[name] = value
14
- end
15
-
16
- def merge(new_hash)
17
- values.merge!(new_hash)
18
- end
19
-
20
- def to_hash
21
- values
22
- end
23
-
24
- protected
25
-
26
- def values
27
- return @inherited_values.merge(@new_values) if @new_values && !@new_values.empty?
28
-
29
- @inherited_values.is_a?(Hash) ? @inherited_values.dup : @inherited_values.to_hash
30
- end
31
- end
32
- end
33
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grape
4
- module Util
5
- class ReverseStackableValues < StackableValues
6
- protected
7
-
8
- def concat_values(inherited_value, new_value)
9
- return inherited_value unless new_value
10
-
11
- new_value + inherited_value
12
- end
13
- end
14
- end
15
- end