Module: IO::Like

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.

Public Instance Methods


ios << obj → ios

Writes obj to the stream using write and returns ios. obj is converted to a String using to_s.

    # File lib/io/like.rb, line 82
82:     def <<(obj)
83:       write(obj)
84:       self
85:     end

ios.binmode → ios

Returns self. Just for compatibility with IO.

    # File lib/io/like.rb, line 91
91:     def binmode
92:       self
93:     end

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.

     # File lib/io/like.rb, line 102
102:     def close
103:       raise IOError, 'closed stream' if closed?
104:       __io_like__close_read
105:       flush if writable?
106:       __io_like__close_write
107:       nil
108:     end

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.

     # File lib/io/like.rb, line 119
119:     def close_read
120:       raise IOError, 'closed stream' if closed?
121:       if __io_like__closed_read? || ! duplexed? && writable? then
122:         raise IOError, 'closing non-duplex IO for reading'
123:       end
124:       if duplexed? then
125:         __io_like__close_read
126:       else
127:         close
128:       end
129:       nil
130:     end

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.

     # File lib/io/like.rb, line 141
141:     def close_write
142:       raise IOError, 'closed stream' if closed?
143:       if __io_like__closed_write? || ! duplexed? && readable? then
144:         raise IOError, 'closing non-duplex IO for reading'
145:       end
146:       if duplexed? then
147:         flush
148:         __io_like__close_write
149:       else
150:         close
151:       end
152:       nil
153:     end

ios.closed? → true or false

Returns true if this object is closed or otherwise unusable for read and write operations.

     # File lib/io/like.rb, line 160
160:     def closed?
161:       (__io_like__closed_read? || ! readable?) &&
162:       (__io_like__closed_write? || ! writable?)
163:     end

ios.duplexed? → true or false

Returns false. Override this to return true when creating duplexed IO objects.

     # File lib/io/like.rb, line 170
170:     def duplexed?
171:       false
172:     end


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.

     # File lib/io/like.rb, line 185
185:     def each_byte
186:       while (byte = getc) do
187:         yield(byte)
188:       end
189:       self
190:     end

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.

     # File lib/io/like.rb, line 204
204:     def each_line(sep_string = $/)
205:       while (line = gets(sep_string)) do
206:         yield(line)
207:       end
208:       self
209:     end

eof ()

Alias for eof?


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.

     # File lib/io/like.rb, line 227
227:     def eof?
228:       if (char = getc) then
229:         ungetc(char)
230:         return false
231:       end
232:       true
233:     end

ios.fcntl

Raises NotImplementedError.

     # File lib/io/like.rb, line 240
240:     def fcntl(*args)
241:       raise NotImplementedError, 'not implemented'
242:     end

ios.fileno → nil

Returns nil. Just for compatibility with IO.

     # File lib/io/like.rb, line 248
248:     def fileno
249:       nil
250:     end

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.

     # File lib/io/like.rb, line 261
261:     def fill_size
262:       raise IOError, 'closed stream' if closed?
263:       raise IOError, 'not opened for reading' unless readable?
264: 
265:       @__io_like__fill_size ||= 4096
266:     end

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.

     # File lib/io/like.rb, line 277
277:     def fill_size=(fill_size)
278:       raise IOError, 'closed stream' if closed?
279:       raise IOError, 'not opened for reading' unless readable?
280: 
281:       unless fill_size >= 0 then
282:         raise ArgumentError, "non-positive fill_size #{fill_size} given"
283:       end
284:       @__io_like__fill_size = fill_size
285:     end

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.

     # File lib/io/like.rb, line 304
304:     def flush
305:       begin
306:         __io_like__buffered_flush
307:       rescue Errno::EAGAIN, Errno::EINTR
308:         retry if write_ready?
309:       end
310:       self
311:     end

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.

     # File lib/io/like.rb, line 322
322:     def flush_size
323:       raise IOError, 'closed stream' if closed?
324:       raise IOError, 'not opened for writing' unless writable?
325: 
326:       @__io_like__flush_size ||= 4096
327:     end

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.

     # File lib/io/like.rb, line 338
338:     def flush_size=(flush_size)
339:       raise IOError, 'closed stream' if closed?
340:       raise IOError, 'not opened for writing' unless writable?
341: 
342:       unless flush_size >= 0 then
343:         raise ArgumentError, "non-positive flush_size #{flush_size} given"
344:       end
345:       @__io_like__flush_size = flush_size
346:     end

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.

     # File lib/io/like.rb, line 363
363:     def getc
364:       readchar
365:     rescue EOFError
366:       nil
367:     end

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.

     # File lib/io/like.rb, line 389
389:     def gets(sep_string = $/)
390:       # Set the last read line in the global.
391:       $_ = readline(sep_string)
392:       # Set the last line number in the global.
393:       $. = lineno
394:       # Return the last read line.
395:       $_
396:     rescue EOFError
397:       nil
398:     end

ios.isatty → false

Returns false. Just for compatibility with IO.

Raises IOError if closed? returns true.

     # File lib/io/like.rb, line 406
406:     def isatty
407:       raise IOError, 'closed stream' if closed?
408:       false
409:     end

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.

     # File lib/io/like.rb, line 422
422:     def lineno
423:       raise IOError, 'closed stream' if closed?
424:       raise IOError, 'not opened for reading' unless readable?
425:       @__io_like__lineno ||= 0
426:     end

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.

     # File lib/io/like.rb, line 437
437:     def lineno=(integer)
438:       raise IOError, 'closed stream' if closed?
439:       raise IOError, 'not opened for reading' unless readable?
440:       if integer.nil? then
441:         raise TypeError, 'no implicit conversion from nil to integer'
442:       elsif ! integer.respond_to?(:to_int) then
443:         raise TypeError, "can't convert #{integer.class} into Integer"
444:       end
445:       @__io_like__lineno = integer.to_int
446:     end

ios.path → nil

Returns nil. Just for compatibility with IO.

     # File lib/io/like.rb, line 452
452:     def path
453:       nil
454:     end

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.

     # File lib/io/like.rb, line 489
489:     def pos
490:       # Flush the internal write buffer for writable, non-duplexed objects.
491:       __io_like__buffered_flush if writable? && ! duplexed?
492:       __io_like__buffered_seek(0, IO::SEEK_CUR)
493:     end

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.

     # File lib/io/like.rb, line 469
469:     def pos=(position)
470:       seek(position, IO::SEEK_SET)
471:       position
472:     end

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.

     # File lib/io/like.rb, line 514
514:     def print(*args)
515:       args << $_ if args.empty?
516:       first_arg = true
517:       args.each do |arg|
518:         # Write a field separator before writing each argument after the first
519:         # one unless no field separator is specified.
520:         if first_arg then
521:           first_arg = false
522:         elsif ! $,.nil? then
523:           write($,)
524:         end
525: 
526:         # If the argument is nil, write 'nil'; otherwise, write the stringified
527:         # form of the argument.
528:         if arg.nil? then
529:           write('nil')
530:         else
531:           write(arg)
532:         end
533:       end
534: 
535:       # Write the output record separator if one is specified.
536:       write($\) unless $\.nil?
537:       nil
538:     end

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.

     # File lib/io/like.rb, line 554
554:     def printf(*args)
555:       write(sprintf(*args))
556:       nil
557:     end

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.

     # File lib/io/like.rb, line 573
573:     def putc(obj)
574:       char = case obj
575:              when String
576:                obj[0].chr
577:              else
578:                [obj.to_int].pack('V')[0].chr
579:              end
580:       write(char)
581:       obj
582:     end

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.

     # File lib/io/like.rb, line 606
606:     def puts(*args)
607:       # Set the output record separator such that this method is compatible with
608:       # IO#puts.
609:       ors = "\n"
610: 
611:       # Write only the record separator if no arguments are given.
612:       if args.length == 0 then
613:         write(ors)
614:         return
615:       end
616: 
617:       # Write each argument followed by the record separator.  Recursively
618:       # process arguments which are Array instances.
619:       args.each do |arg|
620:         line = arg.nil? ?
621:                  'nil' :
622:                  arg.kind_of?(Array) ?
623:                    __io_like__array_join(arg, ors) :
624:                    arg.to_s
625:         line += ors if line.index(ors, -ors.length).nil?
626:         write(line)
627:       end
628: 
629:       nil
630:     end

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.

     # File lib/io/like.rb, line 654
654:     def read(length = nil, buffer = nil)
655:       # Check the validity of the method arguments.
656:       unless length.nil? || length >= 0 then
657:         raise ArgumentError, "negative length #{length} given"
658:       end
659:       buffer = buffer.nil? ? '' : buffer.to_str
660:       buffer.slice!(0..-1) unless buffer.empty?
661: 
662:       if length.nil? then
663:         # Read and return everything.
664:         begin
665:           loop do
666:             buffer << __io_like__buffered_read(4096)
667:           end
668:         rescue EOFError
669:           # Ignore this.
670:         rescue SystemCallError
671:           # Reraise the error if there is nothing to return.
672:           raise if buffer.empty?
673:         end
674:       else
675:         # Read and return up to length bytes.
676:         begin
677:           buffer << __io_like__buffered_read(length)
678:         rescue EOFError
679:           # Return nil to the caller at end of file when requesting a specific
680:           # amount of data.
681:           return nil
682:         end
683:       end
684:       buffer
685:     end

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.

     # File lib/io/like.rb, line 702
702:     def read_ready?
703:       return false unless readable?
704:       sleep(1)
705:       true
706:     end

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.

     # File lib/io/like.rb, line 717
717:     def readable?
718:       ! __io_like__closed_read? && respond_to?(:unbuffered_read, true)
719:     end

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.

     # File lib/io/like.rb, line 738
738:     def readbytes(length)
739:       buffer = read(length)
740:       if buffer.nil? then
741:         raise EOFError, "end of file reached"
742:       end
743:       if buffer.length < length then
744:         raise TruncatedDataError.new("data truncated", buffer)
745:       end
746:       buffer
747:     end

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.

     # File lib/io/like.rb, line 762
762:     def readchar
763:       __io_like__buffered_read(1)[0]
764:     rescue Errno::EAGAIN, Errno::EINTR
765:       retry if read_ready?
766:     end

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.

     # File lib/io/like.rb, line 805
805:     def readline(sep_string = $/)
806:       # Ensure that sep_string is either nil or a String.
807:       unless sep_string.nil? || sep_string.kind_of?(String) then
808:         sep_string = sep_string.to_str
809:       end
810: 
811:       buffer = ''
812:       begin
813:         if sep_string.nil? then
814:           # A nil line separator means that the user wants to capture all the
815:           # remaining input.
816:           loop do
817:             buffer << __io_like__buffered_read(4096)
818:           end
819:         else
820:           begin
821:             # Record if the user requested paragraphs rather than lines.
822:             paragraph_requested = sep_string.empty?
823:             # An empty line separator string indicates that the user wants to
824:             # return paragraphs.  A pair of newlines in the stream is used to
825:             # mark this.
826:             sep_string = "\n\n" if paragraph_requested
827: 
828:             # Add each character from the input to the buffer until either the
829:             # buffer has the right ending or the end of the input is reached.
830:             while buffer.index(sep_string, -sep_string.length).nil? &&
831:                   (char = __io_like__buffered_read(1)) do
832:               buffer << char
833:             end
834: 
835:             if paragraph_requested then
836:               # If the user requested paragraphs instead of lines, we need to
837:               # consume and discard all newlines remaining at the front of the
838:               # input.
839:               while char == "\n" && (char = __io_like__buffered_read(1)) do
840:                 nil
841:               end
842:               # Put back the last character.
843:               ungetc(char[0])
844:             end
845:           rescue Errno::EAGAIN, Errno::EINTR
846:             retry if read_ready?
847:           end
848:         end
849:       rescue EOFError, SystemCallError
850:         # Reraise the error if there is nothing to return.
851:         raise if buffer.empty?
852:       end
853:       # Increment the number of times this method has returned a "line".
854:       self.lineno += 1
855:       buffer
856:     end

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.

     # File lib/io/like.rb, line 881
881:     def readlines(sep_string = $/)
882:       lines = []
883:       each_line(sep_string) { |line| lines << line }
884:       lines
885:     end

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.

     # File lib/io/like.rb, line 905
905:     def readpartial(length, buffer = nil)
906:       # Check the validity of the method arguments.
907:       unless length >= 0 then
908:         raise ArgumentError, "negative length #{length} given"
909:       end
910:       buffer = '' if buffer.nil?
911:       # Flush the buffer.
912:       buffer.slice!(0..-1)
913: 
914:       # Read and return up to length bytes.
915:       if __io_like__internal_read_buffer.empty? then
916:         begin
917:           buffer << __io_like__buffered_read(length)
918:         rescue Errno::EAGAIN, Errno::EINTR
919:           retry if read_ready?
920:         end
921:       else
922:         raise IOError, 'closed stream' if closed?
923:         raise IOError, 'not opened for reading' unless readable?
924: 
925:         buffer << __io_like__internal_read_buffer.slice!(0, length)
926:       end
927:       buffer
928:     end

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.

     # File lib/io/like.rb, line 945
945:     def rewind
946:       seek(0, IO::SEEK_SET)
947:       self.lineno = 0 if readable?
948:       0
949:     end

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.

     # File lib/io/like.rb, line 970
970:     def seek(offset, whence = IO::SEEK_SET)
971:       __io_like__buffered_seek(offset, whence)
972:       0
973:     end

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.

     # File lib/io/like.rb, line 984
984:     def seekable?
985:       ! duplexed? && respond_to?(:unbuffered_seek, true)
986:     end

ios.sync → true or false

Returns true if the internal write buffer is currently being bypassed, false otherwise.

Raises IOError if closed? returns true.

     # File lib/io/like.rb, line 995
995:     def sync
996:       raise IOError, 'closed stream' if closed?
997:       @__io_like__sync ||= false
998:     end

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.

      # File lib/io/like.rb, line 1009
1009:     def sync=(sync)
1010:       raise IOError, 'closed stream' if closed?
1011:       @__io_like__sync = sync ? true : false
1012:     end

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.

      # File lib/io/like.rb, line 1029
1029:     def sysread(length, buffer = nil)
1030:       buffer = buffer.nil? ? '' : buffer.to_str
1031:       buffer.slice!(0..-1) unless buffer.empty?
1032:       return buffer if length == 0
1033: 
1034:       raise IOError, 'closed stream' if closed?
1035:       raise IOError, 'not opened for reading' unless readable?
1036:       unless __io_like__internal_read_buffer.empty? then
1037:         raise IOError, 'sysread on buffered IO'
1038:       end
1039: 
1040:       # Flush the internal write buffer for writable, non-duplexed objects.
1041:       __io_like__buffered_flush if writable? && ! duplexed?
1042: 
1043:       buffer << unbuffered_read(length)
1044:     end

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.

      # File lib/io/like.rb, line 1061
1061:     def sysseek(offset, whence = IO::SEEK_SET)
1062:       raise IOError, 'closed stream' if closed?
1063:       raise Errno::ESPIPE unless seekable?
1064:       unless __io_like__internal_read_buffer.empty? then
1065:         raise IOError, 'sysseek on buffered IO'
1066:       end
1067:       unless __io_like__internal_write_buffer.empty? then
1068:         warn('warning: sysseek on buffered IO')
1069:       end
1070: 
1071:       unbuffered_seek(offset, whence)
1072:     end

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.

      # File lib/io/like.rb, line 1088
1088:     def syswrite(string)
1089:       raise IOError, 'closed stream' if closed?
1090:       raise IOError, 'not opened for writing' unless writable?
1091:       unless __io_like__internal_write_buffer.empty? then
1092:         warn('warning: syswrite on buffered IO')
1093:       end
1094: 
1095:       # Flush the internal read buffer and set the unbuffered position to the
1096:       # buffered position when dealing with non-duplexed objects.
1097:       unless duplexed? || __io_like__internal_read_buffer.empty? then
1098:         unbuffered_seek(-__io_like__internal_read_buffer.length, IO::SEEK_CUR)
1099:         __io_like__internal_read_buffer.slice!(0..-1)
1100:       end
1101: 
1102:       unbuffered_write(string)
1103:     end

tell ()

Alias for pos


ios.to_io → ios

Returns ios.

      # File lib/io/like.rb, line 1109
1109:     def to_io
1110:       self
1111:     end

tty? ()

Alias for isatty


ios.ungetc(integer) → nil

Calls unread with integer.chr as an argument.

Raises IOError if closed? returns true. Raises IOError unless readable? returns true.

      # File lib/io/like.rb, line 1120
1120:     def ungetc(integer)
1121:       unread(integer.chr)
1122:     end

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.

      # File lib/io/like.rb, line 1133
1133:     def unread(string)
1134:       raise IOError, 'closed stream' if closed?
1135:       raise IOError, 'not opened for reading' unless readable?
1136:       __io_like__internal_read_buffer.insert(0, string.to_s)
1137:       nil
1138:     end

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.

      # File lib/io/like.rb, line 1170
1170:     def writable?
1171:       ! __io_like__closed_write? && respond_to?(:unbuffered_write, true)
1172:     end

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.

      # File lib/io/like.rb, line 1190
1190:     def write(string)
1191:       string = string.to_s
1192:       return 0 if string.empty?
1193: 
1194:       bytes_written = 0
1195:       while bytes_written < string.length do
1196:         begin
1197:           bytes_written +=
1198:             __io_like__buffered_write(string.to_s.slice(bytes_written..-1))
1199:         rescue Errno::EAGAIN, Errno::EINTR
1200:           retry if write_ready?
1201:         end
1202:       end
1203:       bytes_written
1204:     end

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.

      # File lib/io/like.rb, line 1155
1155:     def write_ready?
1156:       return false unless writable?
1157:       sleep(1)
1158:       true
1159:     end