Class: IO::Stream::Generic
- Inherits:
-
Object
- Object
- IO::Stream::Generic
- Defined in:
- lib/io/stream/generic.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#block_size ⇒ Object
Returns the value of attribute block_size.
Instance Method Summary collapse
-
#<<(string) ⇒ Object
Writes ‘string` to the stream and returns self.
-
#close ⇒ Object
Best effort to flush any unwritten data, and then close the underling IO.
- #close_read ⇒ Object
- #close_write ⇒ Object
- #closed? ⇒ Boolean
- #eof! ⇒ Object
-
#eof? ⇒ Boolean
Determins if the stream has consumed all available data.
-
#flush ⇒ Object
Flushes buffered data to the stream.
- #gets(separator = $/, **options) ⇒ Object
-
#initialize(block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE) ⇒ Generic
constructor
A new instance of Generic.
- #peek(size = nil) ⇒ Object
- #puts(*arguments, separator: $/) ⇒ Object
-
#read(size = nil) ⇒ Object
Reads ‘size` bytes from the stream.
- #read_exactly(size, exception: EOFError) ⇒ Object
-
#read_partial(size = nil) ⇒ Object
Read at most ‘size` bytes from the stream.
-
#read_until(pattern, offset = 0, limit: nil, chomp: true) ⇒ Object
Efficiently read data from the stream until encountering pattern.
-
#readable? ⇒ Boolean
Whether there is a chance that a read operation will succeed or not.
-
#readpartial(size = nil) ⇒ Object
This is a compatibility shim for existing code that uses ‘readpartial`.
-
#write(string, flush: false) ⇒ Object
Writes ‘string` to the buffer.
Constructor Details
#initialize(block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE) ⇒ Generic
Returns a new instance of Generic.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/io/stream/generic.rb', line 22 def initialize(block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE) @eof = false @writing = ::Thread::Mutex.new @block_size = block_size @maximum_read_size = maximum_read_size @read_buffer = StringBuffer.new @write_buffer = StringBuffer.new # Used as destination buffer for underlying reads. @input_buffer = StringBuffer.new end |
Instance Attribute Details
#block_size ⇒ Object
Returns the value of attribute block_size.
37 38 39 |
# File 'lib/io/stream/generic.rb', line 37 def block_size @block_size end |
Instance Method Details
#<<(string) ⇒ Object
Writes ‘string` to the stream and returns self.
173 174 175 176 177 |
# File 'lib/io/stream/generic.rb', line 173 def <<(string) write(string) return self end |
#close ⇒ Object
Best effort to flush any unwritten data, and then close the underling IO.
203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/io/stream/generic.rb', line 203 def close return if closed? begin flush rescue # We really can't do anything here unless we want #close to raise exceptions. ensure self.sysclose end end |
#close_read ⇒ Object
195 196 |
# File 'lib/io/stream/generic.rb', line 195 def close_read end |
#close_write ⇒ Object
198 199 200 |
# File 'lib/io/stream/generic.rb', line 198 def close_write flush end |
#closed? ⇒ Boolean
191 192 193 |
# File 'lib/io/stream/generic.rb', line 191 def closed? false end |
#eof! ⇒ Object
229 230 231 232 233 234 |
# File 'lib/io/stream/generic.rb', line 229 def eof! @read_buffer.clear @eof = true raise EOFError end |
#eof? ⇒ Boolean
Determins if the stream has consumed all available data. May block if the stream is not readable. See #readable? for a non-blocking alternative.
219 220 221 222 223 224 225 226 227 |
# File 'lib/io/stream/generic.rb', line 219 def eof? if !@read_buffer.empty? return false elsif @eof return true else return !self.fill_read_buffer end end |
#flush ⇒ Object
Flushes buffered data to the stream.
146 147 148 149 150 151 152 |
# File 'lib/io/stream/generic.rb', line 146 def flush return if @write_buffer.empty? @writing.synchronize do self.drain(@write_buffer) end end |
#gets(separator = $/, **options) ⇒ Object
132 133 134 |
# File 'lib/io/stream/generic.rb', line 132 def gets(separator = $/, **) read_until(separator, **) end |
#peek(size = nil) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/io/stream/generic.rb', line 115 def peek(size = nil) if size until @eof or @read_buffer.bytesize >= size # Compute the amount of data we need to read from the underlying stream: read_size = size - @read_buffer.bytesize # Don't read less than @block_size to avoid lots of small reads: fill_read_buffer(read_size > @block_size ? read_size : @block_size) end return @read_buffer[..([size, @read_buffer.size].min - 1)] end until (block_given? && yield(@read_buffer)) or @eof fill_read_buffer end return @read_buffer end |
#puts(*arguments, separator: $/) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/io/stream/generic.rb', line 179 def puts(*arguments, separator: $/) return if arguments.empty? @writing.synchronize do arguments.each do |argument| @write_buffer << argument << separator end self.drain(@write_buffer) end end |
#read(size = nil) ⇒ Object
Reads ‘size` bytes from the stream. If size is not specified, read until end of file.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/io/stream/generic.rb', line 40 def read(size = nil) return String.new(encoding: Encoding::BINARY) if size == 0 if size until @eof or @read_buffer.bytesize >= size # Compute the amount of data we need to read from the underlying stream: read_size = size - @read_buffer.bytesize # Don't read less than @block_size to avoid lots of small reads: fill_read_buffer(read_size > @block_size ? read_size : @block_size) end else until @eof fill_read_buffer end end return consume_read_buffer(size) end |
#read_exactly(size, exception: EOFError) ⇒ Object
71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/io/stream/generic.rb', line 71 def read_exactly(size, exception: EOFError) if buffer = read(size) if buffer.bytesize != size raise exception, "could not read enough data" end return buffer end raise exception, "encountered eof while reading data" end |
#read_partial(size = nil) ⇒ Object
Read at most ‘size` bytes from the stream. Will avoid reading from the underlying stream if possible.
61 62 63 64 65 66 67 68 69 |
# File 'lib/io/stream/generic.rb', line 61 def read_partial(size = nil) return String.new(encoding: Encoding::BINARY) if size == 0 if !@eof and @read_buffer.empty? fill_read_buffer end return consume_read_buffer(size) end |
#read_until(pattern, offset = 0, limit: nil, chomp: true) ⇒ Object
Efficiently read data from the stream until encountering pattern.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/io/stream/generic.rb', line 93 def read_until(pattern, offset = 0, limit: nil, chomp: true) # We don't want to split on the pattern, so we subtract the size of the pattern. split_offset = pattern.bytesize - 1 until index = @read_buffer.index(pattern, offset) offset = @read_buffer.bytesize - split_offset offset = 0 if offset < 0 return nil if limit and offset >= limit return nil unless fill_read_buffer end return nil if limit and index >= limit @read_buffer.freeze matched = @read_buffer.byteslice(0, index+(chomp ? 0 : pattern.bytesize)) @read_buffer = @read_buffer.byteslice(index+pattern.bytesize, @read_buffer.bytesize) return matched end |
#readable? ⇒ Boolean
Whether there is a chance that a read operation will succeed or not.
238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/io/stream/generic.rb', line 238 def readable? # If we are at the end of the file, we can't read any more data: if @eof return false end # If the read buffer is not empty, we can read more data: if !@read_buffer.empty? return true end # If the underlying stream is readable, we can read more data: return !closed? end |
#readpartial(size = nil) ⇒ Object
This is a compatibility shim for existing code that uses ‘readpartial`.
84 85 86 |
# File 'lib/io/stream/generic.rb', line 84 def readpartial(size = nil) read_partial(size) or raise EOFError, "Encountered eof while reading data!" end |
#write(string, flush: false) ⇒ Object
Writes ‘string` to the buffer. When the buffer is full or #sync is true the buffer is flushed to the underlying `io`.
158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/io/stream/generic.rb', line 158 def write(string, flush: false) @writing.synchronize do @write_buffer << string flush |= (@write_buffer.bytesize >= @block_size) if flush self.drain(@write_buffer) end end return string.bytesize end |