Module: IO::Like
- Includes:
- Enumerable
- Defined in:
- lib/io/like.rb
Overview
IO::Like is a module which provides most of the basic input and output functions of IO objects using methods named unbuffered_read, unbuffered_write, and unbuffered_seek.
Readers
In order to use this module to provide input methods, a class which includes it must provide the unbuffered_read method which takes one argument, a length, as follows:
def unbuffered_read(length)
...
end
This method must return at most length bytes as a String, raise EOFError if reading begins at the end of data, and raise SystemCallError on error. Errno::EAGAIN should be raised if there is no data to return immediately and the read operation should not block. Errno::EINTR should be raised if the read operation is interrupted before any data is read.
Writers
In order to use this module to provide output methods, a class which includes it must provide the unbuffered_write method which takes a single string argument as follows:
def unbuffered_write(string)
...
end
This method must either return the number of bytes written to the stream, which may be less than the length of string in bytes, OR must raise an instance of SystemCallError. Errno::EAGAIN should be raised if no data can be written immediately and the write operation should not block. Errno::EINTR should be raised if the write operation is interrupted before any data is written.
Seekers
In order to use this module to provide seeking methods, a class which includes it must provide the unbuffered_seek method which takes two required arguments, an offset and a start position, as follows:
def unbuffered_seek(offset, whence)
...
end
This method must return the new position within the data stream relative to the beginning of the stream and should raise SystemCallError on error. offset can be any integer and whence can be any of IO::SEEK_SET, IO::SEEK_CUR, or IO::SEEK_END. They are interpreted together as follows:
whence | resulting position
-------------+------------------------------------------------------------
IO::SEEK_SET | Add offset to the position of the beginning of the stream.
-------------+------------------------------------------------------------
IO::SEEK_CUR | Add offset to the current position of the stream.
-------------+------------------------------------------------------------
IO::SEEK_END | Add offset to the position of the end of the stream.
Duplexed Streams
In order to create a duplexed stream where writing and reading happen independently of each other, override the #duplexed? method to return true
and then provide the unbuffered_read and unbuffered_write methods. Do NOT provide an unbuffered_seek method or the contents of the internal read and write buffers may be lost unexpectedly.
NOTE: Due to limitations of Ruby’s finalizer, IO::Like#close is not automatically called when the object is garbage collected, so it must be explicitly called when the object is no longer needed or risk losing whatever data remains in the internal write buffer.
Instance Method Summary collapse
-
#<<(obj) ⇒ Object
call-seq: ios << obj -> ios.
-
#binmode ⇒ Object
call-seq: ios.binmode -> ios.
-
#close ⇒ Object
call-seq: ios.close -> nil.
-
#close_read ⇒ Object
call-seq: ios.close_read -> nil.
-
#close_write ⇒ Object
call-seq: ios.close_write -> nil.
-
#closed? ⇒ Boolean
call-seq: ios.closed? -> true or false.
-
#duplexed? ⇒ Boolean
call-seq: ios.duplexed? -> true or false.
-
#each_byte ⇒ Object
call-seq: ios.each_byte { |byte| block } -> ios.
-
#each_line(sep_string = $/) ⇒ Object
(also: #each)
call-seq: ios.each_line(sep_string = $/) { |line| block } -> ios ios.each(sep_string = $/) { |line| block } -> ios.
-
#eof? ⇒ Boolean
(also: #eof)
call-seq: ios.eof? -> true or false ios.eof -> true or false.
-
#fcntl(*args) ⇒ Object
call-seq: ios.fcntl.
-
#fileno ⇒ Object
call-seq: ios.fileno -> nil.
-
#fill_size ⇒ Object
call-seq: ios.fill_size -> integer.
-
#fill_size=(fill_size) ⇒ Object
call-seq: ios.fill_size = integer -> integer.
-
#flush ⇒ Object
call-seq: ios.flush -> ios.
-
#flush_size ⇒ Object
call-seq: ios.flush_size -> integer.
-
#flush_size=(flush_size) ⇒ Object
call-seq: ios.flush_size = integer -> integer.
-
#getc ⇒ Object
call-seq: ios.getc -> nil or integer.
-
#gets(sep_string = $/) ⇒ Object
call-seq: ios.gets(sep_string = $/) -> nil or string.
-
#isatty ⇒ Object
(also: #tty?)
call-seq: ios.isatty -> false.
-
#lineno ⇒ Object
call-seq: ios.lineno -> integer.
-
#lineno=(integer) ⇒ Object
call-seq: ios.lineno = lineno -> lineno.
-
#path ⇒ Object
call-seq: ios.path -> nil.
-
#pos ⇒ Object
(also: #tell)
call-seq: ios.pos -> integer.
-
#pos=(position) ⇒ Object
call-seq: ios.pos = position -> position.
-
#print(*args) ⇒ Object
call-seq: ios.print([obj, …]) -> nil.
-
#printf(*args) ⇒ Object
call-seq: ios.printf(format_string [, obj, …]) -> nil.
-
#putc(obj) ⇒ Object
call-seq: ios.putc(obj) -> obj.
-
#puts(*args) ⇒ Object
call-seq: ios.puts([obj, …]) -> nil.
-
#read(length = nil, buffer = nil) ⇒ Object
call-seq: ios.read([length[, buffer]]) -> nil, buffer, or string.
-
#read_ready? ⇒ Boolean
call-seq: ios.read_ready? -> true or false.
-
#readable? ⇒ Boolean
call-seq: ios.readable? -> true or false.
-
#readbytes(length) ⇒ Object
call-seq: ios.readbytes(length) -> string.
-
#readchar ⇒ Object
call-seq: ios.readchar -> integer.
-
#readline(sep_string = $/) ⇒ Object
call-seq: ios.readline(sep_string = $/) -> string.
-
#readlines(sep_string = $/) ⇒ Object
call-seq: ios.readlines(sep_string = $/) -> array.
-
#readpartial(length, buffer = nil) ⇒ Object
call-seq: ios.readpartial(length[, buffer]) -> string or buffer.
-
#rewind ⇒ Object
call-seq: ios.rewind -> 0.
-
#seek(offset, whence = IO::SEEK_SET) ⇒ Object
call-seq: seek(offset[, whence]) -> 0.
-
#seekable? ⇒ Boolean
call-seq: ios.seekable? -> true or false.
-
#sync ⇒ Object
call-seq: ios.sync -> true or false.
-
#sync=(sync) ⇒ Object
call-seq: ios.sync = boolean -> boolean.
-
#sysread(length, buffer = nil) ⇒ Object
call-seq: ios.sysread(length) -> string.
-
#sysseek(offset, whence = IO::SEEK_SET) ⇒ Object
call-seq: ios.sysseek(offset[, whence]) -> integer.
-
#syswrite(string) ⇒ Object
call-seq: ios.syswrite(string) -> integer.
-
#to_io ⇒ Object
call-seq: ios.to_io -> ios.
-
#ungetc(integer) ⇒ Object
call-seq: ios.ungetc(integer) -> nil.
-
#unread(string) ⇒ Object
call-seq: ios.unread(string) -> nil.
-
#writable? ⇒ Boolean
call-seq: ios.writable? -> true or false.
-
#write(string) ⇒ Object
call-seq: ios.write(string) -> integer.
-
#write_ready? ⇒ Boolean
call-seq: ios.write_ready? -> true or false.
Instance Method Details
#<<(obj) ⇒ Object
call-seq:
ios << obj -> ios
Writes obj to the stream using #write and returns ios. obj is converted to a String using to_s.
82 83 84 85 |
# File 'lib/io/like.rb', line 82 def <<(obj) write(obj) self end |
#binmode ⇒ Object
call-seq:
ios.binmode -> ios
Returns self
. Just for compatibility with IO.
91 92 93 |
# File 'lib/io/like.rb', line 91 def binmode self end |
#close ⇒ Object
call-seq:
ios.close -> nil
Arranges for #closed? to return true
. Raises IOError if #closed? already returns true
. For duplexed objects, calls #close_read and #close_write. For non-duplexed objects, calls #flush if #writable? returns true
and then sets a flag so that #closed? will return true
.
102 103 104 105 106 107 108 |
# File 'lib/io/like.rb', line 102 def close raise IOError, 'closed stream' if closed? __io_like__close_read flush if writable? __io_like__close_write nil end |
#close_read ⇒ Object
call-seq:
ios.close_read -> nil
Closes the read end of a duplexed object or the whole object if the object is read-only.
Raises IOError if #closed? returns true
. Raises IOError for duplexed objects if called more than once. Raises IOError for non-duplexed objects if #writable? returns true
.
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/io/like.rb', line 119 def close_read raise IOError, 'closed stream' if closed? if __io_like__closed_read? || ! duplexed? && writable? then raise IOError, 'closing non-duplex IO for reading' end if duplexed? then __io_like__close_read else close end nil end |
#close_write ⇒ Object
call-seq:
ios.close_write -> nil
Closes the write end of a duplexed object or the whole object if the object is write-only.
Raises IOError if #closed? returns true
. Raises IOError for duplexed objects if called more than once. Raises IOError for non-duplexed objects if #readable? returns true
.
141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/io/like.rb', line 141 def close_write raise IOError, 'closed stream' if closed? if __io_like__closed_write? || ! duplexed? && readable? then raise IOError, 'closing non-duplex IO for reading' end if duplexed? then flush __io_like__close_write else close end nil end |
#closed? ⇒ Boolean
call-seq:
ios.closed? -> true or false
Returns true
if this object is closed or otherwise unusable for read and write operations.
160 161 162 163 |
# File 'lib/io/like.rb', line 160 def closed? (__io_like__closed_read? || ! readable?) && (__io_like__closed_write? || ! writable?) end |
#duplexed? ⇒ Boolean
call-seq:
ios.duplexed? -> true or false
Returns false
. Override this to return true
when creating duplexed IO objects.
170 171 172 |
# File 'lib/io/like.rb', line 170 def duplexed? false end |
#each_byte ⇒ Object
call-seq:
ios.each_byte { |byte| block } -> ios
Reads each byte (0..255) from the stream using #getc and calls the given block once for each byte, passing the byte as an argument.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError results into nil
results, this method will also raise the same errors and block at the same times as #unbuffered_read.
185 186 187 188 189 190 |
# File 'lib/io/like.rb', line 185 def each_byte while (byte = getc) do yield(byte) end self end |
#each_line(sep_string = $/) ⇒ Object Also known as: each
call-seq:
ios.each_line(sep_string = $/) { |line| block } -> ios
ios.each(sep_string = $/) { |line| block } -> ios
Reads each line from the stream using #gets and calls the given block once for each line, passing the line as an argument.
NOTE: When sep_string is not nil
, this method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError results into nil
results, this method will also raise the same errors and block at the same times as #unbuffered_read.
204 205 206 207 208 209 |
# File 'lib/io/like.rb', line 204 def each_line(sep_string = $/) while (line = gets(sep_string)) do yield(line) end self end |
#eof? ⇒ Boolean Also known as: eof
call-seq:
ios.eof? -> true or false
ios.eof -> true or false
Returns true
if there is no more data to read.
This works by using #getc to fetch the next character and using #ungetc to put the character back if one was fetched. It may be a good idea to replace this implementation in derivative classes.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError results into nil
results, this method will also raise the same errors and block at the same times as #unbuffered_read.
227 228 229 230 231 232 233 |
# File 'lib/io/like.rb', line 227 def eof? if (char = getc) then ungetc(char) return false end true end |
#fcntl(*args) ⇒ Object
call-seq:
ios.fcntl
Raises NotImplementedError.
240 241 242 |
# File 'lib/io/like.rb', line 240 def fcntl(*args) raise NotImplementedError, 'not implemented' end |
#fileno ⇒ Object
call-seq:
ios.fileno -> nil
Returns nil
. Just for compatibility with IO.
248 249 250 |
# File 'lib/io/like.rb', line 248 def fileno nil end |
#fill_size ⇒ Object
call-seq:
ios.fill_size -> integer
Returns the number of bytes to read as a block whenever the internal buffer needs to be refilled. Unless set explicitly via #fill_size=, this defaults to 4096.
Raises IOError if #closed? returns true
. Raises IOError if the stream is not opened for reading.
261 262 263 264 265 266 |
# File 'lib/io/like.rb', line 261 def fill_size raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? @__io_like__fill_size ||= 4096 end |
#fill_size=(fill_size) ⇒ Object
call-seq:
ios.fill_size = integer -> integer
Sets the number of bytes to read as a block whenever the internal read buffer needs to be refilled. The new value must be a number greater than or equal to 0. Setting this to 0 effectively disables buffering.
Raises IOError if #closed? returns true
. Raises IOError if the stream is not opened for reading.
277 278 279 280 281 282 283 284 285 |
# File 'lib/io/like.rb', line 277 def fill_size=(fill_size) raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? unless fill_size >= 0 then raise ArgumentError, "non-positive fill_size #{fill_size} given" end @__io_like__fill_size = fill_size end |
#flush ⇒ Object
call-seq:
ios.flush -> ios
Flushes the internal write buffer to the underlying data stream.
Regardless of the blocking status of the data stream or interruptions during writing, this method will block until either all the data is flushed or until an error is raised.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_write. Therefore, this method always blocks if unable to flush the internal write buffer. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_write.
304 305 306 307 308 309 310 311 |
# File 'lib/io/like.rb', line 304 def flush begin __io_like__buffered_flush rescue Errno::EAGAIN, Errno::EINTR retry if write_ready? end self end |
#flush_size ⇒ Object
call-seq:
ios.flush_size -> integer
Returns the number of bytes at which the internal write buffer is flushed automatically to the data stream. Unless set explicitly via #flush_size=, this defaults to 4096.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
322 323 324 325 326 327 |
# File 'lib/io/like.rb', line 322 def flush_size raise IOError, 'closed stream' if closed? raise IOError, 'not opened for writing' unless writable? @__io_like__flush_size ||= 4096 end |
#flush_size=(flush_size) ⇒ Object
call-seq:
ios.flush_size = integer -> integer
Sets the number of bytes at which the internal write buffer is flushed automatically to the data stream. The new value must be a number greater than or equal to 0. Setting this to 0 effectively disables buffering.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
338 339 340 341 342 343 344 345 346 |
# File 'lib/io/like.rb', line 338 def flush_size=(flush_size) raise IOError, 'closed stream' if closed? raise IOError, 'not opened for writing' unless writable? unless flush_size >= 0 then raise ArgumentError, "non-positive flush_size #{flush_size} given" end @__io_like__flush_size = flush_size end |
#getc ⇒ Object
call-seq:
ios.getc -> nil or integer
Calls #readchar and either returns the result or nil
if #readchar raises EOFError.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
. Raises all errors raised by #unbuffered_read except for EOFError.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks. Aside from that exception and the conversion of EOFError results into nil
results, this method will also raise the same errors and block at the same times as #unbuffered_read.
363 364 365 366 367 |
# File 'lib/io/like.rb', line 363 def getc readchar rescue EOFError nil end |
#gets(sep_string = $/) ⇒ Object
call-seq:
ios.gets(sep_string = $/) -> nil or string
Calls #readline with sep_string as an argument and either returns the result or nil
if #readline raises EOFError. If #readline returns some data, $.
is set to the value of #lineno.
NOTE: Due to limitations of MRI up to version 1.9.x when running managed (Ruby) code, this method fails to set $_
to the returned data; however, other implementations may allow it.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
. Raises all errors raised by #unbuffered_read except for EOFError.
NOTE: When sep_string is not nil
, this method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method will always block in that case. Aside from that exception, this method will raise the same errors and block at the same times as #unbuffered_read.
389 390 391 392 393 394 395 396 397 398 |
# File 'lib/io/like.rb', line 389 def gets(sep_string = $/) # Set the last read line in the global. $_ = readline(sep_string) # Set the last line number in the global. $. = lineno # Return the last read line. $_ rescue EOFError nil end |
#isatty ⇒ Object Also known as: tty?
call-seq:
ios.isatty -> false
Returns false
. Just for compatibility with IO.
Raises IOError if #closed? returns true
.
406 407 408 409 |
# File 'lib/io/like.rb', line 406 def isatty raise IOError, 'closed stream' if closed? false end |
#lineno ⇒ Object
call-seq:
ios.lineno -> integer
Returns the number of times #gets was called and returned non-nil
data. By default this is the number of lines read, but calling #gets or any of the other line-based reading methods with a non-default value for sep_string or after changing $/
will affect this.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
422 423 424 425 426 |
# File 'lib/io/like.rb', line 422 def lineno raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? @__io_like__lineno ||= 0 end |
#lineno=(integer) ⇒ Object
call-seq:
ios.lineno = lineno -> lineno
Sets the current line number to the given value. $.
is updated by the next call to #gets. If the object given is not an integer, it is converted to one using its to_int method.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
437 438 439 440 441 442 443 444 445 446 |
# File 'lib/io/like.rb', line 437 def lineno=(integer) raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? if integer.nil? then raise TypeError, 'no implicit conversion from nil to integer' elsif ! integer.respond_to?(:to_int) then raise TypeError, "can't convert #{integer.class} into Integer" end @__io_like__lineno = integer.to_int end |
#path ⇒ Object
call-seq:
ios.path -> nil
Returns nil
. Just for compatibility with IO.
452 453 454 |
# File 'lib/io/like.rb', line 452 def path nil end |
#pos ⇒ Object Also known as: tell
call-seq:
ios.pos -> integer
Returns the current offest of ios.
Raises IOError if #closed? returns true
. Raises Errno::ESPIPE unless #seekable? returns true
.
As a side effect, the internal write buffer is flushed unless this is a writable, non-duplexed object. This is for compatibility with the behavior of IO#pos.
NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write (when the internal write buffer is not empty), it will also raise the same errors and block at the same times as those functions.
489 490 491 492 493 |
# File 'lib/io/like.rb', line 489 def pos # Flush the internal write buffer for writable, non-duplexed objects. __io_like__buffered_flush if writable? && ! duplexed? __io_like__buffered_seek(0, IO::SEEK_CUR) end |
#pos=(position) ⇒ Object
call-seq:
ios.pos = position -> position
Sets the data position to position by calling #seek.
As a side effect, the internal read and write buffers are flushed.
Raises IOError if #closed? returns true
. Raises Errno::ESPIPE unless #seekable? returns true
.
NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write (when the internal write buffer is not empty), it will also raise the same errors and block at the same times as those functions.
469 470 471 472 |
# File 'lib/io/like.rb', line 469 def pos=(position) seek(position, IO::SEEK_SET) position end |
#print(*args) ⇒ Object
call-seq:
ios.print([obj, ...]) -> nil
Writes the given object(s), if any, to the stream using #write after converting them to strings by calling their to_s methods. If no objects are given, $_
is used. The field separator ($,
) is written between successive objects if it is not nil
. The output record separator ($\
) is written after all other data if it is not nil.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_write. Therefore, this method always blocks if unable to immediately write [obj, …] completely. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_write.
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
# File 'lib/io/like.rb', line 514 def print(*args) args << $_ if args.empty? first_arg = true args.each do |arg| # Write a field separator before writing each argument after the first # one unless no field separator is specified. if first_arg then first_arg = false elsif ! $,.nil? then write($,) end # If the argument is nil, write 'nil'; otherwise, write the stringified # form of the argument. if arg.nil? then write('nil') else write(arg) end end # Write the output record separator if one is specified. write($\) unless $\.nil? nil end |
#printf(*args) ⇒ Object
call-seq:
ios.printf(format_string [, obj, ...]) -> nil
Writes the String returned by calling Kernel.sprintf using the given arguments.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_write. Therefore, this method always blocks if unable to immediately write its arguments completely. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_write.
554 555 556 557 |
# File 'lib/io/like.rb', line 554 def printf(*args) write(sprintf(*args)) nil end |
#putc(obj) ⇒ Object
call-seq:
ios.putc(obj) -> obj
If obj is a String, write the first byte; otherwise, convert obj to a integer using its to_int method and write the low order byte.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_write. Therefore, this method always blocks if unable to immediately write obj completely. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_write.
573 574 575 576 577 578 579 580 581 582 |
# File 'lib/io/like.rb', line 573 def putc(obj) char = case obj when String obj[0].chr else [obj.to_int].pack('V')[0].chr end write(char) obj end |
#puts(*args) ⇒ Object
call-seq:
ios.puts([obj, ...]) -> nil
Writes the given object(s), if any, to the stream using #write after converting them to strings using their to_s methods. Unlike #print, Array instances are recursively processed. A record separator character is written after each object which does not end with the record separator already. If no objects are given, a single record separator is written.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_write. Therefore, this method always blocks if unable to immediately write [obj, …] completely. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_write.
NOTE: In order to be compatible with IO#puts, the record separator is currently hardcoded to be a single newline ("\n"
) even though the documentation implies that the output record separator ($\
) should be used.
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/io/like.rb', line 606 def puts(*args) # Set the output record separator such that this method is compatible with # IO#puts. ors = "\n" # Write only the record separator if no arguments are given. if args.length == 0 then write(ors) return end # Write each argument followed by the record separator. Recursively # process arguments which are Array instances. args.each do |arg| line = arg.nil? ? 'nil' : arg.kind_of?(Array) ? __io_like__array_join(arg, ors) : arg.to_s line += ors if line.index(ors, -ors.length).nil? write(line) end nil end |
#read(length = nil, buffer = nil) ⇒ Object
call-seq:
ios.read([length[, buffer]]) -> nil, buffer, or string
If length is specified and is a positive integer, at most length bytes are returned. Truncated data will occur if there is insufficient data left to fulfill the request. If the read starts at the end of data, nil
is returned.
If length is unspecified or nil
, an attempt to return all remaining data is made. Partial data will be returned if a low-level error is raised after some data is retrieved. If no data would be returned at all, an empty String is returned.
If buffer is specified, it will be converted to a String using its to_str
method if necessary and will be filled with the returned data if any.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
NOTE: Because this method relies on #unbuffered_read, it will also raise the same errors and block at the same times as that function.
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
# File 'lib/io/like.rb', line 654 def read(length = nil, buffer = nil) # Check the validity of the method arguments. unless length.nil? || length >= 0 then raise ArgumentError, "negative length #{length} given" end buffer = buffer.nil? ? '' : buffer.to_str buffer.slice!(0..-1) unless buffer.empty? if length.nil? then # Read and return everything. begin loop do buffer << __io_like__buffered_read(4096) end rescue EOFError # Ignore this. rescue SystemCallError # Reraise the error if there is nothing to return. raise if buffer.empty? end else # Read and return up to length bytes. begin buffer << __io_like__buffered_read(length) rescue EOFError # Return nil to the caller at end of file when requesting a specific # amount of data. return nil end end buffer end |
#read_ready? ⇒ Boolean
call-seq:
ios.read_ready? -> true or false
Returns true
when the stream may be read without error, false
otherwise. This method will block until one of the conditions is known.
This default implementation of #read_ready? is a hack which should be able to work for both real IO objects and IO-like objects; however, it is inefficient since it merely sleeps for 1 second and then returns true
as long as #closed? returns false
. IO.select should be used for real IO objects to wait for a readable condition on platforms with support for IO.select. Other solutions should be found as necessary to improve this implementation on a case by case basis.
Basically, this method should be overridden in derivative classes.
702 703 704 705 706 |
# File 'lib/io/like.rb', line 702 def read_ready? return false unless readable? sleep(1) true end |
#readable? ⇒ Boolean
call-seq:
ios.readable? -> true or false
Returns true
if the stream is both open and readable, false
otherwise.
This implementation checks to see if #unbuffered_read is defined in order to make its determination. Override this if the implementing class always provides the #unbuffered_read method but may not always be open in a readable mode.
717 718 719 |
# File 'lib/io/like.rb', line 717 def readable? ! __io_like__closed_read? && respond_to?(:unbuffered_read, true) end |
#readbytes(length) ⇒ Object
call-seq:
ios.readbytes(length) -> string
Reads and returns length bytes from the data stream.
Raises EOFError if reading begins at the end of the stream. Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
. Raises TruncatedDataError if insufficient data is immediately available to satisfy the request.
In the case of TruncatedDataError being raised, the retrieved data can be fetched from the data attribute of the exception.
This method is basically copied from IO#readbytes.
NOTE: Because this method relies on #unbuffered_read, it will also raise the same errors and block at the same times as that function.
738 739 740 741 742 743 744 745 746 747 |
# File 'lib/io/like.rb', line 738 def readbytes(length) buffer = read(length) if buffer.nil? then raise EOFError, "end of file reached" end if buffer.length < length then raise TruncatedDataError.new("data truncated", buffer) end buffer end |
#readchar ⇒ Object
call-seq:
ios.readchar -> integer
Returns the next 8-bit byte (0..255) from the stream.
Raises EOFError when there is no more data in the stream. Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_read.
762 763 764 765 766 |
# File 'lib/io/like.rb', line 762 def readchar __io_like__buffered_read(1)[0] rescue Errno::EAGAIN, Errno::EINTR retry if read_ready? end |
#readline(sep_string = $/) ⇒ Object
call-seq:
ios.readline(sep_string = $/) -> string
Returns the next line from the stream, where lines are separated by sep_string. Increments #lineno by 1
for each call regardless of the value of sep_string.
If sep_string is not nil
and not a String, it is first converted to a String using its to_str
method and processing continues as follows.
If sep_string is nil
, a line is defined as the remaining contents of the stream. Partial data will be returned if a low-level error of any kind is raised after some data is retrieved. This is equivalent to calling #read without any arguments except that this method will raise an EOFError if called at the end of the stream.
If sep_string is an empty String, a paragraph is returned, where a paragraph is defined as data followed by 2 or more successive newline characters. A maximum of 2 newlines are returned at the end of the returned data. Fewer may be returned if the stream ends before at least 2 successive newlines are seen.
Any other value for sep_string is used as a delimiter to mark the end of a line. The returned data includes this delimiter unless the stream ends before the delimiter is seen.
In any case, the end of the stream terminates the current line.
Raises EOFError when there is no more data in the stream. Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
NOTE: When sep_string is not nil
, this method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method will always block in that case. Aside from that exception, this method will raise the same errors and block at the same times as #unbuffered_read.
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 |
# File 'lib/io/like.rb', line 805 def readline(sep_string = $/) # Ensure that sep_string is either nil or a String. unless sep_string.nil? || sep_string.kind_of?(String) then sep_string = sep_string.to_str end buffer = '' begin if sep_string.nil? then # A nil line separator means that the user wants to capture all the # remaining input. loop do buffer << __io_like__buffered_read(4096) end else begin # Record if the user requested paragraphs rather than lines. paragraph_requested = sep_string.empty? # An empty line separator string indicates that the user wants to # return paragraphs. A pair of newlines in the stream is used to # mark this. sep_string = "\n\n" if paragraph_requested # Add each character from the input to the buffer until either the # buffer has the right ending or the end of the input is reached. while buffer.index(sep_string, -sep_string.length).nil? && (char = __io_like__buffered_read(1)) do buffer << char end if paragraph_requested then # If the user requested paragraphs instead of lines, we need to # consume and discard all newlines remaining at the front of the # input. while char == "\n" && (char = __io_like__buffered_read(1)) do nil end # Put back the last character. ungetc(char[0]) end rescue Errno::EAGAIN, Errno::EINTR retry if read_ready? end end rescue EOFError, SystemCallError # Reraise the error if there is nothing to return. raise if buffer.empty? end # Increment the number of times this method has returned a "line". self.lineno += 1 buffer end |
#readlines(sep_string = $/) ⇒ Object
call-seq:
ios.readlines(sep_string = $/) -> array
Returns an Array containing the lines in the stream using #each_line.
If sep_string is nil
, a line is defined as the remaining contents of the stream. If sep_string is not a String, it is converted to one using its to_str
method. If sep_string is empty, a paragraph is returned, where a paragraph is defined as data followed by 2 or more successive newline characters (only 2 newlines are returned at the end of the returned data).
In any case, the end of the stream terminates the current line.
Raises EOFError when there is no more data in the stream. Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
NOTE: When sep_string is not nil
, this method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_read.
881 882 883 884 885 |
# File 'lib/io/like.rb', line 881 def readlines(sep_string = $/) lines = [] each_line(sep_string) { |line| lines << line } lines end |
#readpartial(length, buffer = nil) ⇒ Object
call-seq:
ios.readpartial(length[, buffer]) -> string or buffer
Returns at most length bytes from the data stream using only the internal read buffer if the buffer is not empty. Falls back to reading from the stream if the buffer is empty. Blocks if no data is available from either the internal read buffer or the data stream regardless of whether or not the data stream would block.
Raises EOFError when there is no more data in the stream. Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_read. Therefore, this method always blocks if unable to immediately return length bytes. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_read.
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 |
# File 'lib/io/like.rb', line 905 def readpartial(length, buffer = nil) # Check the validity of the method arguments. unless length >= 0 then raise ArgumentError, "negative length #{length} given" end buffer = '' if buffer.nil? # Flush the buffer. buffer.slice!(0..-1) # Read and return up to length bytes. if __io_like__internal_read_buffer.empty? then begin buffer << __io_like__buffered_read(length) rescue Errno::EAGAIN, Errno::EINTR retry if read_ready? end else raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? buffer << __io_like__internal_read_buffer.slice!(0, length) end buffer end |
#rewind ⇒ Object
call-seq:
ios.rewind -> 0
Sets the position of the file pointer to the beginning of the stream and returns 0 when complete. The lineno attribute is reset to 0 if successful and the stream is readable according to #readable?.
As a side effect, the internal read and write buffers are flushed.
Raises IOError if #closed? returns true
. Raises Errno::ESPIPE unless #seekable? returns true
.
NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write (when the internal write buffer is not empty), it will also raise the same errors and block at the same times as those functions.
945 946 947 948 949 |
# File 'lib/io/like.rb', line 945 def rewind seek(0, IO::SEEK_SET) self.lineno = 0 if readable? 0 end |
#seek(offset, whence = IO::SEEK_SET) ⇒ Object
call-seq:
seek(offset[, whence]) -> 0
Sets the current data position to offset based on the setting of whence. If whence is unspecified or IO::SEEK_SET, offset counts from the beginning of the data. If whence is IO::SEEK_END, offset counts from the end of the data (offset should be negative here). If whence is IO::SEEK_CUR, offset is relative to the current position.
As a side effect, the internal read and write buffers are flushed except when seeking relative to the current position (whence is IO::SEEK_CUR) to a location within the internal read buffer.
Raises IOError if #closed? returns true
. Raises Errno::ESPIPE unless #seekable? returns true
.
NOTE: Because this method relies on #unbuffered_seek and #unbuffered_write (when the internal write buffer is not empty), it will also raise the same errors and block at the same times as those functions.
970 971 972 973 |
# File 'lib/io/like.rb', line 970 def seek(offset, whence = IO::SEEK_SET) __io_like__buffered_seek(offset, whence) 0 end |
#seekable? ⇒ Boolean
call-seq:
ios.seekable? -> true or false
Returns true
if the stream is seekable, false
otherwise.
This implementation always returns false
for duplexed objects and checks to see if #unbuffered_seek is defined in order to make its determination otherwise. Override this if the implementing class always provides the #unbuffered_seek method but may not always be seekable.
984 985 986 |
# File 'lib/io/like.rb', line 984 def seekable? ! duplexed? && respond_to?(:unbuffered_seek, true) end |
#sync ⇒ Object
call-seq:
ios.sync -> true or false
Returns true if the internal write buffer is currently being bypassed, false otherwise.
Raises IOError if #closed? returns true
.
995 996 997 998 |
# File 'lib/io/like.rb', line 995 def sync raise IOError, 'closed stream' if closed? @__io_like__sync ||= false end |
#sync=(sync) ⇒ Object
call-seq:
ios.sync = boolean -> boolean
When set to true
the internal write buffer will be bypassed. Any data currently in the buffer will be flushed prior to the next output operation. When set to false
, the internal write buffer will be enabled.
Raises IOError if #closed? returns true
.
1009 1010 1011 1012 |
# File 'lib/io/like.rb', line 1009 def sync=(sync) raise IOError, 'closed stream' if closed? @__io_like__sync = sync ? true : false end |
#sysread(length, buffer = nil) ⇒ Object
call-seq:
ios.sysread(length) -> string
Reads and returns up to length bytes directly from the data stream, bypassing the internal read buffer.
Returns ""
if length is 0 regardless of the status of the data stream. This is for compatibility with IO#sysread.
Raises EOFError if reading begins at the end of the stream. Raises IOError if the internal read buffer is not empty. Raises IOError if #closed? returns true
.
NOTE: Because this method relies on #unbuffered_read, it will also raise the same errors and block at the same times as that function.
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 |
# File 'lib/io/like.rb', line 1029 def sysread(length, buffer = nil) buffer = buffer.nil? ? '' : buffer.to_str buffer.slice!(0..-1) unless buffer.empty? return buffer if length == 0 raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? unless __io_like__internal_read_buffer.empty? then raise IOError, 'sysread on buffered IO' end # Flush the internal write buffer for writable, non-duplexed objects. __io_like__buffered_flush if writable? && ! duplexed? buffer << unbuffered_read(length) end |
#sysseek(offset, whence = IO::SEEK_SET) ⇒ Object
call-seq:
ios.sysseek(offset[, whence]) -> integer
Sets the current data position to offset based on the setting of whence. If whence is unspecified or IO::SEEK_SET, offset counts from the beginning of the data. If whence is IO::SEEK_END, offset counts from the end of the data (offset should be negative here). If whence is IO::SEEK_CUR, offset is relative to the current position.
Raises IOError if the internal read buffer is not empty. Raises IOError if #closed? returns true
. Raises Errno::ESPIPE unless #seekable? returns true
.
NOTE: Because this method relies on #unbuffered_seek, it will also raise the same errors and block at the same times as that function.
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 |
# File 'lib/io/like.rb', line 1061 def sysseek(offset, whence = IO::SEEK_SET) raise IOError, 'closed stream' if closed? raise Errno::ESPIPE unless seekable? unless __io_like__internal_read_buffer.empty? then raise IOError, 'sysseek on buffered IO' end unless __io_like__internal_write_buffer.empty? then warn('warning: sysseek on buffered IO') end unbuffered_seek(offset, whence) end |
#syswrite(string) ⇒ Object
call-seq:
ios.syswrite(string) -> integer
Writes string directly to the data stream, bypassing the internal write buffer and returns the number of bytes written.
As a side effect for non-duplex objects, the internal read buffer is flushed.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: Because this method relies on #unbuffered_write, it will also raise the same errors and block at the same times as that function.
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 |
# File 'lib/io/like.rb', line 1088 def syswrite(string) raise IOError, 'closed stream' if closed? raise IOError, 'not opened for writing' unless writable? unless __io_like__internal_write_buffer.empty? then warn('warning: syswrite on buffered IO') end # Flush the internal read buffer and set the unbuffered position to the # buffered position when dealing with non-duplexed objects. unless duplexed? || __io_like__internal_read_buffer.empty? then unbuffered_seek(-__io_like__internal_read_buffer.length, IO::SEEK_CUR) __io_like__internal_read_buffer.slice!(0..-1) end unbuffered_write(string) end |
#to_io ⇒ Object
call-seq:
ios.to_io -> ios
Returns ios.
1109 1110 1111 |
# File 'lib/io/like.rb', line 1109 def to_io self end |
#ungetc(integer) ⇒ Object
call-seq:
ios.ungetc(integer) -> nil
Calls #unread with integer.chr
as an argument.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
1120 1121 1122 |
# File 'lib/io/like.rb', line 1120 def ungetc(integer) unread(integer.chr) end |
#unread(string) ⇒ Object
call-seq:
ios.unread(string) -> nil
Pushes the given string onto the front of the internal read buffer and returns nil
. If string is not a String, it is converted to one using its to_s
method.
Raises IOError if #closed? returns true
. Raises IOError unless #readable? returns true
.
1133 1134 1135 1136 1137 1138 |
# File 'lib/io/like.rb', line 1133 def unread(string) raise IOError, 'closed stream' if closed? raise IOError, 'not opened for reading' unless readable? __io_like__internal_read_buffer.insert(0, string.to_s) nil end |
#writable? ⇒ Boolean
call-seq:
ios.writable? -> true or false
Returns true
if the stream is both open and writable, false
otherwise.
This implementation checks to see if #unbuffered_write is defined in order to make its determination. Override this if the implementing class always provides the #unbuffered_write method but may not always be open in a writable mode.
1170 1171 1172 |
# File 'lib/io/like.rb', line 1170 def writable? ! __io_like__closed_write? && respond_to?(:unbuffered_write, true) end |
#write(string) ⇒ Object
call-seq:
ios.write(string) -> integer
Writes the given string to the stream and returns the number of bytes written. If string is not a String, its to_s
method is used to convert it into one. The entire contents of string are written, blocking as necessary even if the data stream does not block.
Raises IOError if #closed? returns true
. Raises IOError unless #writable? returns true
.
NOTE: This method ignores Errno::EAGAIN and Errno::EINTR raised by #unbuffered_write. Therefore, this method always blocks if unable to immediately write string completely. Aside from that exception, this method will also raise the same errors and block at the same times as #unbuffered_write.
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 |
# File 'lib/io/like.rb', line 1190 def write(string) string = string.to_s return 0 if string.empty? bytes_written = 0 while bytes_written < string.length do begin bytes_written += __io_like__buffered_write(string.to_s.slice(bytes_written..-1)) rescue Errno::EAGAIN, Errno::EINTR retry if write_ready? end end bytes_written end |
#write_ready? ⇒ Boolean
call-seq:
ios.write_ready? -> true or false
Returns true
when the stream may be written without error, false
otherwise. This method will block until one of the conditions is known.
This default implementation of #write_ready? is a hack which should be able to work for both real IO objects and IO-like objects; however, it is inefficient since it merely sleeps for 1 second and then returns true
as long as #closed? returns false
. IO.select should be used for real IO objects to wait for a writeable condition on platforms with support for IO.select. Other solutions should be found as necessary to improve this implementation on a case by case basis.
Basically, this method should be overridden in derivative classes.
1155 1156 1157 1158 1159 |
# File 'lib/io/like.rb', line 1155 def write_ready? return false unless writable? sleep(1) true end |