IO::Stream
Provide a buffered stream implementation for Ruby, independent of the underlying IO.
Motivation
I built this gem because working with IO in Ruby can be surprisingly difficult. Ruby provides buffering, but the inconsistencies between different IO types made it impossible to write clean, generic code. OpenSSL::SSL::SSLSocket maintains its own buffering implementation that behaves differently from regular IO. Some IO types raise OpenSSL::SSL::SSLError on connection reset while others raise Errno::ECONNRESET. EOF semantics vary. Close operations can hang (especially with SSL sockets). And if you want to work with non-blocking IO using read_nonblock and write_nonblock, you're constantly handling :wait_readable and :wait_writable conditions, managing timeouts, and dealing with edge cases that differ across implementations.
By providing a standard interface for buffered IO, io-stream allows you to write code that works the same way regardless of the underlying IO type. You can wrap any IO object and get consistent buffering behavior, unified error handling, and proper management of blocking/non-blocking operations. This makes it much easier to write high-performance IO code without worrying about the quirks of each specific IO implementation. Over time, as we've upstreamed more fixes into Ruby, we've been able to reduce the number of workarounds needed, but the core value of io-stream remains: a single, predictable interface for all your IO needs.
Usage
Please browse the source code index or refer to the guides below.
Getting Started
This guide explains how to use io-stream to add efficient buffering to Ruby IO objects.
High Performance IO
This guide explains how to achieve optimal performance when using io-stream by understanding and controlling flush behavior.
Releases
Please browse the releases for more details.
Unreleased
- Remove old OpenSSL method shims.
v0.11.0
- Introduce
class IO::Stream::ConnectionResetError < Errno::ECONNRESETto standardize connection reset error handling across different IO types.OpenSSL::SSL::SSLSocketraisesOpenSSL::SSL::SSLErroron connection reset, while other IO types raiseErrno::ECONNRESET.SSLErroris now rescued and re-raised asIO::Stream::ConnectionResetErrorfor consistency.
v0.10.0
- Rename
done?tofinished?for clarity and consistency.
v0.9.1
- Fix EOF behavior to match Ruby IO semantics:
read()returns empty string""at EOF whileread(size)returnsnilat EOF.
v0.9.0
- Add support for
bufferparameter inread,read_exactly, andread_partialmethods to allow reading into a provided buffer.
v0.8.0
- On Ruby v3.3+, use
IO#writedirectly instead ofIO#write_nonblock, for better performance. - Introduce support for
Readable#discard_untilmethod to discard data until a specific pattern is found.
v0.7.0
- Split stream functionality into separate
ReadableandWritablemodules for better modularity and composition. - Remove unused timeout shim functionality.
- 100% documentation coverage.
v0.6.1
- Fix compatibility with Ruby v3.3.0 - v3.3.6 where broken
@io.closecould hang.
v0.6.0
- Improve compatibility of
getsimplementation to better match Ruby's IO#gets behavior.
v0.5.0
- Add support for
read_until(limit:)parameter to limit the amount of data read. - Minor documentation improvements.
See Also
- async-io — Where this implementation originally came from.
Contributing
We welcome contributions to this project.
- Fork it.
- Create your feature branch (
git checkout -b my-new-feature). - Commit your changes (
git commit -am 'Add some feature'). - Push to the branch (
git push origin my-new-feature). - Create new Pull Request.
Running Tests
To run the test suite:
bundle exec sus
Making Releases
To make a new release:
bundle exec bake gem:release:patch # or minor or major
Developer Certificate of Origin
In order to protect users of this project, we require all contributors to comply with the Developer Certificate of Origin. This ensures that all contributions are properly licensed and attributed.
Community Guidelines
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.