Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions lib/protocol/rack/body/enumerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Copyright, 2022-2026, by Samuel Williams.

require "protocol/http/body/readable"
require "protocol/http/body/buffered"
require "protocol/http/body/file"

module Protocol
Expand All @@ -23,9 +24,9 @@ class Enumerable < ::Protocol::HTTP::Body::Readable
# @parameter length [Integer] Optional content length of the response body.
# @returns [Enumerable] A new enumerable body instance.
def self.wrap(body, length = nil)
if body.is_a?(Array)
length ||= body.sum(&:bytesize)
return self.new(body, length)
if body.respond_to?(:to_ary)
# This avoids allocating an enumerator, which is more efficient:
return ::Protocol::HTTP::Body::Buffered.new(body.to_ary, length)
else
return self.new(body, length)
end
Expand Down
4 changes: 2 additions & 2 deletions test/protocol/rack/adapter/rack2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
let(:app) {->(env){[200, {}, body]}}

it "should not modify partial responses" do
expect(response.body).to be_a(Protocol::Rack::Body::Enumerable)
expect(response.body).to be_a(Protocol::HTTP::Body::Buffered)
end
end
end
Expand All @@ -78,7 +78,7 @@
let(:app) {->(env){[200, {}, ["Hello"]]}}

it "handles array response correctly" do
expect(response.body).to be_a(Protocol::Rack::Body::Enumerable)
expect(response.body).to be_a(Protocol::HTTP::Body::Buffered)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/protocol/rack/adapter/rack3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
let(:app) {->(env){[200, {}, fake_file]}}

it "should not modify partial responses" do
expect(response.body).to be(:kind_of?, Protocol::Rack::Body::Enumerable)
expect(response.body).to be(:kind_of?, Protocol::HTTP::Body::Buffered)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/protocol/rack/adapter/rack31.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
let(:app) {->(env){[200, {}, fake_file]}}

it "should not modify partial responses" do
expect(response.body).to be(:kind_of?, Protocol::Rack::Body::Enumerable)
expect(response.body).to be(:kind_of?, Protocol::HTTP::Body::Buffered)
end
end
end
Expand Down
35 changes: 35 additions & 0 deletions test/protocol/rack/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,41 @@ def body.each
end
end

with "array body" do
it "wraps array body and returns chunks via #read" do
result = subject.wrap(env, 200, headers, ["Hello", " ", "World"])

expect(result).not.to be_nil
expect(result.read).to be == "Hello"
expect(result.read).to be == " "
expect(result.read).to be == "World"
expect(result.read).to be_nil
end

it "wraps array body and yields chunks via #each" do
result = subject.wrap(env, 200, headers, ["chunk1", "chunk2"])
chunks = []
result.each{|chunk| chunks << chunk}

expect(chunks).to be == ["chunk1", "chunk2"]
end

it "wraps empty array body" do
result = subject.wrap(env, 200, headers, [])

expect(result).not.to be_nil
expect(result).to be(:empty?)
expect(result.read).to be_nil
end

it "uses content-length when provided" do
headers["content-length"] = "11"
result = subject.wrap(env, 200, headers, ["Hello", " World"])

expect(result.length).to be == 11
end
end

with "response finished callback" do
it "returns a body that calls the callback when closed" do
called = false
Expand Down
18 changes: 18 additions & 0 deletions test/protocol/rack/body/enumerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@
end
end

with "#read" do
let(:body) {subject.new(["Hello", " ", "World"], 11)}

it "returns chunks in order" do
expect(body.read).to be == "Hello"
expect(body.read).to be == " "
expect(body.read).to be == "World"
expect(body.read).to be_nil
end

it "returns nil when exhausted" do
body.read
body.read
body.read
expect(body.read).to be_nil
end
end

with "#each" do
let(:bad_enumerable) do
Enumerator.new do |yielder|
Expand Down
Loading