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

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

#binmodeObject

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

#closeObject

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.

Raises:

  • (IOError)


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_readObject

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.

Raises:

  • (IOError)


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_writeObject

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.

Raises:

  • (IOError)


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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


170
171
172
# File 'lib/io/like.rb', line 170

def duplexed?
  false
end

#each_byteObject

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.

Returns:

  • (Boolean)


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.

Raises:

  • (NotImplementedError)


240
241
242
# File 'lib/io/like.rb', line 240

def fcntl(*args)
  raise NotImplementedError, 'not implemented'
end

#filenoObject

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_sizeObject

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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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

#flushObject

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_sizeObject

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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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

#getcObject

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

#isattyObject Also known as: tty?

call-seq:

ios.isatty           -> false

Returns false. Just for compatibility with IO.

Raises IOError if #closed? returns true.

Raises:

  • (IOError)


406
407
408
409
# File 'lib/io/like.rb', line 406

def isatty
  raise IOError, 'closed stream' if closed?
  false
end

#linenoObject

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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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

#pathObject

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

#posObject 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

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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


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

#readcharObject

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

#rewindObject

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.

Returns:

  • (Boolean)


984
985
986
# File 'lib/io/like.rb', line 984

def seekable?
  ! duplexed? && respond_to?(:unbuffered_seek, true)
end

#syncObject

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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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.

Raises:

  • (IOError)


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_ioObject

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.

Raises:

  • (IOError)


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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


1155
1156
1157
1158
1159
# File 'lib/io/like.rb', line 1155

def write_ready?
  return false unless writable?
  sleep(1)
  true
end