class Proxy::Dynflow::IOBuffer

A buffer around an IO object providing buffering and convenience methods for non-blocking reads and writes.

@note Using a single IOBuffer with a single IO for both reads and writes might not be a good idea. If you need to use a single IO for both reads and writes, wrap it in two separate IOBuffers.

@attr_accessor [IO] io The IO which the buffer wraps @attr_reader [String] buffer The buffer where the data read from the underlying IO is buffered

Attributes

buffer[R]
io[RW]

Public Class Methods

new(io) click to toggle source

@param [IO] io The IO object to be buffered

# File lib/smart_proxy_dynflow/io_buffer.rb, line 17
def initialize(io)
  @buffer = ''
  @io = io
end

Public Instance Methods

add_data(data) click to toggle source

Adds data to the buffer. If the buffer is used for writing, then this should be the preferred method of queueing the data to be written.

@return [void]

# File lib/smart_proxy_dynflow/io_buffer.rb, line 102
def add_data(data)
  @buffer += data
end
close() click to toggle source

Closes the underlying IO. Does nothing if the IO is already closed.

@return [void]

# File lib/smart_proxy_dynflow/io_buffer.rb, line 65
def close
  @io.close unless @io.closed?
end
closed?() click to toggle source

Checks whether the underlying IO is empty

@return [true, false] whether the underlying IO is empty

# File lib/smart_proxy_dynflow/io_buffer.rb, line 58
def closed?
  @io.closed?
end
empty?() click to toggle source

Checks whether the buffer is empty

@return [true, false] whether the buffer is empty

# File lib/smart_proxy_dynflow/io_buffer.rb, line 51
def empty?
  @buffer.empty?
end
on_data(&block) click to toggle source

Sets a callback to be executed each time data is read from the underlying IO.

@note Note that if the callback is provided, the buffer will store the return value of the callback instead of the raw data.

@yieldparam [String] data read from the underlying IO @yieldreturn [String] data to be buffered @return [void]

# File lib/smart_proxy_dynflow/io_buffer.rb, line 30
def on_data(&block)
  @callback = block
end
read_available!() click to toggle source

Reads all the data that is currently waiting in the IO and stores it. If EOFError is encountered during the read, the underlying IO is closed.

@return [void]

# File lib/smart_proxy_dynflow/io_buffer.rb, line 73
def read_available!
  data = ''
  loop { data += @io.read_nonblock(4096) }
rescue IO::WaitReadable # rubocop:disable Lint/SuppressedException
rescue EOFError
  close
ensure
  @buffer += with_callback(data) unless data.empty?
end
to_io() click to toggle source

Exposes the underlying IO so that the buffer itself can be used in IO.select calls.

@return [IO] the underlying IO

# File lib/smart_proxy_dynflow/io_buffer.rb, line 37
def to_io
  @io
end
to_s() click to toggle source

Exposes the contents of the buffer as a String

@return [String] the buffered data

# File lib/smart_proxy_dynflow/io_buffer.rb, line 44
def to_s
  @buffer
end
write_available!() click to toggle source

Writes all the data into the IO that can be written without blocking. It is a no-op if there are no data to be written. If an EOFError is encountered during the write, the underlying IO is closed.

@return [void]

# File lib/smart_proxy_dynflow/io_buffer.rb, line 88
def write_available!
  until @buffer.empty?
    n = @io.write_nonblock(@buffer)
    @buffer = @buffer.bytes.drop(n).pack('c*')
  end
rescue IO::WaitWritable # rubocop:disable Lint/SuppressedException
rescue EOFError
  close
end

Private Instance Methods

with_callback(data) click to toggle source
# File lib/smart_proxy_dynflow/io_buffer.rb, line 108
def with_callback(data)
  if @callback
    @callback.call(data)
  else
    data
  end
end