Skip to content

Commit 3a6f404

Browse files
committed
Rack 2 should not use to_ary. Fixes #35.
1 parent 9610faa commit 3a6f404

4 files changed

Lines changed: 43 additions & 26 deletions

File tree

lib/protocol/rack/adapter.rb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Released under the MIT License.
44
# Copyright, 2022-2026, by Samuel Williams.
55

6-
require "rack"
6+
require_relative "adapter/version"
77

88
module Protocol
99
module Rack
@@ -16,9 +16,6 @@ module Rack
1616
# response = adapter.call(request)
1717
# ```
1818
module Adapter
19-
# The version of Rack being used. Can be overridden using the PROTOCOL_RACK_ADAPTER_VERSION environment variable.
20-
VERSION = ENV.fetch("PROTOCOL_RACK_ADAPTER_VERSION", ::Rack.release)
21-
2219
if VERSION >= "3.1"
2320
require_relative "adapter/rack31"
2421
IMPLEMENTATION = Rack31
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2022-2026, by Samuel Williams.
5+
6+
require "rack"
7+
8+
module Protocol
9+
module Rack
10+
module Adapter
11+
# The version of Rack being used. Can be overridden using the PROTOCOL_RACK_ADAPTER_VERSION environment variable.
12+
VERSION = ENV.fetch("PROTOCOL_RACK_ADAPTER_VERSION", ::Rack.release)
13+
end
14+
end
15+
end

lib/protocol/rack/body/enumerable.rb

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
require "protocol/http/body/buffered"
88
require "protocol/http/body/file"
99

10+
require_relative "../adapter/version"
11+
1012
module Protocol
1113
module Rack
1214
module Body
@@ -17,18 +19,30 @@ class Enumerable < ::Protocol::HTTP::Body::Readable
1719
# The content-length header key.
1820
CONTENT_LENGTH = "content-length".freeze
1921

20-
# Wraps a Rack response body into an {Enumerable} instance.
21-
# If the body is an Array, its total size is calculated automatically.
22-
#
23-
# @parameter body [Object] The Rack response body that responds to `each`.
24-
# @parameter length [Integer] Optional content length of the response body.
25-
# @returns [Enumerable] A new enumerable body instance.
26-
def self.wrap(body, length = nil)
27-
if body.respond_to?(:to_ary)
28-
# This avoids allocating an enumerator, which is more efficient:
29-
return ::Protocol::HTTP::Body::Buffered.new(body.to_ary, length)
30-
else
31-
return self.new(body, length)
22+
if Adapter::VERSION >= "3"
23+
# Wraps a Rack response body into an {Enumerable} instance.
24+
# If the body is an Array, its total size is calculated automatically.
25+
#
26+
# @parameter body [Object] The Rack response body that responds to `each`.
27+
# @parameter length [Integer] Optional content length of the response body.
28+
# @returns [Enumerable] A new enumerable body instance.
29+
def self.wrap(body, length = nil)
30+
if body.respond_to?(:to_ary)
31+
# This avoids allocating an enumerator, which is more efficient:
32+
return ::Protocol::HTTP::Body::Buffered.new(body.to_ary, length)
33+
else
34+
return self.new(body, length)
35+
end
36+
end
37+
else
38+
def self.wrap(body, length = nil)
39+
# Rack 2 does not specify or implement `to_ary` behaviour correctly, so the best we can do is check if it's an Array directly:
40+
if body.is_a?(Array)
41+
# This avoids allocating an enumerator, which is more efficient:
42+
return ::Protocol::HTTP::Body::Buffered.new(body, length)
43+
else
44+
return self.new(body, length)
45+
end
3246
end
3347
end
3448

test/protocol/rack/body/enumerable.rb

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@
55

66
require "protocol/rack/body/enumerable"
77

8-
begin
9-
require "rack"
10-
rescue LoadError
11-
# Rack not available
12-
end
13-
148
describe Protocol::Rack::Body::Enumerable do
159
with "empty body" do
1610
let(:body) {subject.new([], nil)}
@@ -110,10 +104,7 @@
110104
wrapped = subject.wrap(rack_body)
111105

112106
# Read all chunks
113-
chunks = []
114-
while chunk = wrapped.read
115-
chunks << chunk
116-
end
107+
wrapped.join
117108

118109
# The close callback should have been called
119110
expect(closed).to be == true

0 commit comments

Comments
 (0)