grape 3.3.0 → 3.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 533a2014e54eb4dd9c7932addb910af89c6d99f5717133cb081ba7e6d44676cc
4
- data.tar.gz: bd0195007c0d69f4b92a2ca7651ff5e861639dc7a480540dece110877713573a
3
+ metadata.gz: 47f5b2c65d5d4fb054f4b602fd97bd02be043e1ae40ded0d52dc70c2888a4ca7
4
+ data.tar.gz: f6bb78e2afc50d777dc0edf0447098908b6532c7e523f0291e693aacbff065c6
5
5
  SHA512:
6
- metadata.gz: d2967df7dd98a67aee9f0923883f4bec90a107292fd6fd6201a26d9c5aad9961fd75323cfad5ce0e3008925434a613f61590f41dadc73f5c06939cba4719a929
7
- data.tar.gz: a3c9d88a32f75330d680fecbec0a01a8425acf742381c76831fd674fa440e5aae0591c72e58dc8b21e7bf5978fd6f1c865487eba110d5dd47410ab91ff624536
6
+ metadata.gz: 910ad023e4cbfca1ba429adcccaa71018e5bad3f88e2195fe8becb26aa4736ed18b5b87f997e71fa11d4211e817f5b6d2aff518fda31ad93105b6e51c6f4d4b7
7
+ data.tar.gz: 85f489446889da6c3645842672790246e66b636d63af6d3734a8bbaa5163c3ec22086e6e066cda8eac52dfd1c4f4834f4536aab39211585297ab25b1efa4d6d9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### 3.3.2 (2026-07-05)
2
+
3
+ #### Fixes
4
+
5
+ * [#2773](https://github.com/ruby-grape/grape/pull/2773): Fix middleware build crash when a top-level `::Options` constant is in scope - [@ericproulx](https://github.com/ericproulx).
6
+ * Your contribution here.
7
+
8
+ ### 3.3.1 (2026-06-28)
9
+
10
+ #### Fixes
11
+
12
+ * [#2770](https://github.com/ruby-grape/grape/pull/2770): Avoid per-entry array allocation in `Request#build_headers` - [@ericproulx](https://github.com/ericproulx).
13
+ * [#2771](https://github.com/ruby-grape/grape/pull/2771): Fix double wrap on json errors - [@MattHall](https://github.com/MattHall).
14
+
1
15
  ### 3.3.0 (2026-06-20)
2
16
 
3
17
  #### Features
data/README.md CHANGED
@@ -10,7 +10,7 @@ Grape is a REST-like API framework for Ruby. It's designed to run on Rack or com
10
10
 
11
11
  ## Stable Release
12
12
 
13
- You're reading the documentation for the stable release of Grape, 3.3.0.
13
+ You're reading the documentation for the stable release of Grape, 3.3.2.
14
14
 
15
15
  ## Project Resources
16
16
 
@@ -11,14 +11,16 @@ module Grape
11
11
  private
12
12
 
13
13
  def wrap_message(message)
14
- case message
15
- when Hash
16
- message
17
- when Exceptions::ValidationErrors
18
- message.as_json
19
- else
20
- { error: ensure_utf8(message) }
21
- end
14
+ # Use +is_a?+ rather than +case/when+ here. +case/when Hash+ matches via
15
+ # +Module#===+, a C-level real-class check that ignores delegation, so a
16
+ # +SimpleDelegator+ wrapping a Hash (e.g. the +OutputBuilder+ returned by
17
+ # +Grape::Entity#serializable_hash+ when an error is presented via an entity)
18
+ # would fall through and be wrapped in a spurious +{ error: ... }+ envelope.
19
+ # +is_a?+ is forwarded by the delegator to the wrapped Hash, so it matches.
20
+ return message if message.is_a?(Hash)
21
+ return message.as_json if message.is_a?(Exceptions::ValidationErrors)
22
+
23
+ { error: ensure_utf8(message) }
22
24
  end
23
25
 
24
26
  def ensure_utf8(message)
@@ -16,10 +16,8 @@ module Grape
16
16
  # subclass's `DEFAULT_OPTIONS` Hash (legacy path) and frozen.
17
17
  def initialize(app, **options)
18
18
  @app = app
19
- if self.class.const_defined?(:Options)
20
- # Search ancestors so subclasses (e.g. Versioner::Path → Versioner::Base)
21
- # inherit their parent's Options Data class without redeclaring it.
22
- @config = self.class::Options.new(**options)
19
+ if (config_class = options_data_class)
20
+ @config = config_class.new(**options)
23
21
  @options = @config.to_h.freeze
24
22
  else
25
23
  @options = merge_default_options(options).freeze
@@ -92,9 +90,25 @@ module Grape
92
90
 
93
91
  def merge_default_options(options)
94
92
  return default_options.deep_merge(options) if respond_to?(:default_options)
95
- return self.class::DEFAULT_OPTIONS.deep_merge(options) if self.class.const_defined?(:DEFAULT_OPTIONS)
96
93
 
97
- options
94
+ default_options_constant&.deep_merge(options) || options
95
+ end
96
+
97
+ # self.class::Options honours middleware inheritance (e.g. Versioner::Path
98
+ # → Versioner::Base) and, unlike const_defined?, never resolves a
99
+ # top-level ::Options on Object. Absent an own/inherited Options class,
100
+ # the lookup raises NameError and we fall back to the legacy path.
101
+ def options_data_class
102
+ self.class::Options
103
+ rescue NameError
104
+ nil
105
+ end
106
+
107
+ # Same idea as {#options_data_class} for the legacy DEFAULT_OPTIONS Hash.
108
+ def default_options_constant
109
+ self.class::DEFAULT_OPTIONS
110
+ rescue NameError
111
+ nil
98
112
  end
99
113
 
100
114
  def try_scrub(obj)
data/lib/grape/request.rb CHANGED
@@ -177,13 +177,19 @@ module Grape
177
177
  raise Grape::Exceptions::RequestError
178
178
  end
179
179
 
180
+ # Uses a plain `each_header` block instead of `each_header.with_object`:
181
+ # `with_object` can only pass the block one value plus the memo, so the
182
+ # `k, v` pair would be boxed into a throwaway Array on every header. A
183
+ # two-arg block receives `k`/`v` directly and allocates nothing extra.
180
184
  def build_headers
181
- each_header.with_object(Grape::Util::Header.new) do |(k, v), headers|
185
+ headers = Grape::Util::Header.new
186
+ each_header do |k, v|
182
187
  next unless k.start_with? 'HTTP_'
183
188
 
184
189
  transformed_header = KNOWN_HEADERS.fetch(k) { -k[5..].tr('_', '-').downcase }
185
190
  headers[transformed_header] = v
186
191
  end
192
+ headers
187
193
  end
188
194
  end
189
195
  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 = '3.3.0'
5
+ VERSION = '3.3.2'
6
6
  end
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.0
4
+ version: 3.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -281,9 +281,9 @@ licenses:
281
281
  - MIT
282
282
  metadata:
283
283
  bug_tracker_uri: https://github.com/ruby-grape/grape/issues
284
- changelog_uri: https://github.com/ruby-grape/grape/blob/v3.3.0/CHANGELOG.md
285
- documentation_uri: https://www.rubydoc.info/gems/grape/3.3.0
286
- source_code_uri: https://github.com/ruby-grape/grape/tree/v3.3.0
284
+ changelog_uri: https://github.com/ruby-grape/grape/blob/v3.3.2/CHANGELOG.md
285
+ documentation_uri: https://www.rubydoc.info/gems/grape/3.3.2
286
+ source_code_uri: https://github.com/ruby-grape/grape/tree/v3.3.2
287
287
  rubygems_mfa_required: 'true'
288
288
  rdoc_options: []
289
289
  require_paths:
@@ -299,7 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
299
299
  - !ruby/object:Gem::Version
300
300
  version: '0'
301
301
  requirements: []
302
- rubygems_version: 4.0.10
302
+ rubygems_version: 4.0.14
303
303
  specification_version: 4
304
304
  summary: A simple Ruby framework for building REST-like APIs.
305
305
  test_files: []