class Enumerable
Wraps a Rack response body that responds to each.
The body must only yield String values and may optionally respond to close.
This class provides both streaming and buffered access to the response body.
Definitions
CONTENT_LENGTH = "content-length".freeze
The content-length header key.
def self.wrap(body, length = nil)
Wraps a Rack response body into an class Protocol::Rack::Body::Enumerable instance.
If the body is an Array, its total size is calculated automatically.
Signature
-
parameter
bodyObject The Rack response body that responds to
each.-
parameter
lengthInteger Optional content length of the response body.
-
returns
Enumerable A new enumerable body instance.
Implementation
def self.wrap(body, length = nil)
if body.is_a?(Array)
length ||= body.sum(&:bytesize)
return self.new(body, length)
else
return self.new(body, length)
end
end
def initialize(body, length)
Initialize the enumerable body wrapper.
Signature
-
parameter
bodyObject The Rack response body that responds to
each.-
parameter
lengthInteger The content length of the response body.
Implementation
def initialize(body, length)
@length = length
@body = body
@chunks = nil
end
attr :body
Signature
-
attribute
Object The wrapped Rack response body.
attr :length
Signature
-
attribute
Integer The total size of the response body in bytes.
def empty?
Check if the response body is empty.
A body is considered empty if its length is 0 or if it responds to empty? and is empty.
Signature
-
returns
Boolean True if the body is empty.
Implementation
def empty?
@length == 0 or (@body.respond_to?(:empty?) and @body.empty?)
end
def ready?
Check if the response body can be read immediately.
A body is ready if it's an Array or responds to to_ary.
Signature
-
returns
Boolean True if the body can be read immediately.
Implementation
def ready?
body.is_a?(Array) or body.respond_to?(:to_ary)
end
def close(error = nil)
Close the response body.
If the body responds to close, it will be called.
Signature
-
parameter
errorException Optional error that occurred during processing.
Implementation
def close(error = nil)
if @body and @body.respond_to?(:close)
@body.close
end
@body = nil
@chunks = nil
super
end
def each(&block)
Enumerate the response body. Each chunk yielded must be a String. The body is automatically closed after enumeration.
Signature
-
yields
{|chunk| ...} -
parameter
chunkString A chunk of the response body.
-
parameter
Implementation
def each(&block)
@body.each(&block)
rescue => error
raise
ensure
self.close(error)
end
def stream?
Check if the body is a streaming response.
A body is streaming if it doesn't respond to each.
Signature
-
returns
Boolean True if the body is streaming.
Implementation
def stream?
!@body.respond_to?(:each)
end
def call(stream)
Stream the response body to the given stream. The body is automatically closed after streaming.
Signature
-
parameter
streamObject The stream to write the body to.
Implementation
def call(stream)
@body.call(stream)
rescue => error
raise
ensure
self.close(error)
end
def read
Read the next chunk from the response body. Returns nil when there are no more chunks.
Signature
-
returns
String | Nil The next chunk or nil if there are no more chunks.
Implementation
def read
@chunks ||= @body.to_enum(:each)
return @chunks.next
rescue StopIteration
return nil
end
def inspect
Get a string representation of the body.
Signature
-
returns
String A string describing the body's class and length.
Implementation
def inspect
"\#<#{self.class} length=#{@length.inspect} body=#{@body.class}>"
end