Class: IO::LikeHelpers::AbstractIO Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/io/like_helpers/abstract_io.rb

Overview

This class is abstract.

It defines the structure expected of low level streams and largely reflects the structure of the IO class, but most methods raise NotImplementedError. Only the most basic semantics for stream opening and closing are provided.

Direct Known Subclasses

DelegatedIO

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**kwargs) ⇒ AbstractIO

TODO:

Remove explicit ‘kwargs` parameter when Ruby 2.6 support is dropped.

Creates a new instance of this class.

Parameters:

  • kwargs (Hash)

    only provided for compatibility with .open on Ruby 2.6



50
51
52
# File 'lib/io/like_helpers/abstract_io.rb', line 50

def initialize(**kwargs)
  @closed = false
end

Class Method Details

.open(*args, **kwargs) ⇒ Object .open(*args, **kwargs) {|stream| ... } ⇒ block result

Overloads:

  • .open(*args, **kwargs) ⇒ Object

    Equivalent to #initialize.

    Returns:

    • a new instances of this class

  • .open(*args, **kwargs) {|stream| ... } ⇒ block result

    Yields the new instance of this class to the block, ensures the instance is closed once the block completes, and returns the result of the block.

    Yield Parameters:

    • stream

      an instance of this class

    Returns:

    • (block result)

Parameters:

  • args

    a list of arguments passed to the initializer of this class

  • kwargs

    a list of keyword arguments passed to the initializer of this class



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/io/like_helpers/abstract_io.rb', line 28

def self.open(*args, **kwargs)
  io = new(*args, **kwargs)
  return io unless block_given?

  begin
    yield(io)
  ensure
    while Symbol === io.close do
      warn 'warning: waiting for nonblocking close to complete at the end of the open method'
      # A wait timeout is used in order to allow a retry in case the stream
      # was closed in another thread while waiting.
      io.wait(IO::READABLE | IO::WRITABLE, 1)
    end
  end
end

Instance Method Details

#advise(advice, offset = 0, len = 0) ⇒ nil

Announces an intention to access data from the stream in a specific pattern.

This method is a no-op if not implemented. If ‘offset` and `len` are both `0`, then the entire stream is affected.

| ‘advice` | Meaning | | ——– | ——- | | `:normal` | No advice given; default assumption for the stream. | | `:sequential` | The data will be read sequentially from lower offsets to higher ones. | | `:random` | The data will be accessed in random order. | | `:willneed` | The data will be accessed in the near future. | | `:dontneed` | The data will not be accessed in the near future. | | `:noreuse` | The data will only be accessed once. |

See ‘posix_fadvise(2)` for more details.

Parameters:

  • advice (Symbol)

    the access pattern

  • offset (Integer) (defaults to: 0)

    the starting location of the data that will be accessed

  • len (Integer) (defaults to: 0)

    the length of the data that will be accessed

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is closed



79
80
81
# File 'lib/io/like_helpers/abstract_io.rb', line 79

def advise(advice, offset = 0, len = 0)
  nil
end

#closenil, ...

Closes the stream.

Most operations on the stream after this method is called will result in IOErrors being raised.

Returns:

  • (nil)

    on success

  • (:wait_readable, :wait_writable)

    if the stream is non-blocking and the operation would block



92
93
94
95
# File 'lib/io/like_helpers/abstract_io.rb', line 92

def close
  @closed = true
  nil
end

#close_on_exec=(close_on_exec) ⇒ Boolean

Sets the close-on-exec flag for the underlying file descriptor.

Note that setting this to ‘false` can lead to file descriptor leaks in multithreaded applications that fork and exec or use the `system` method.

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


112
113
114
# File 'lib/io/like_helpers/abstract_io.rb', line 112

def close_on_exec=(close_on_exec)
  raise NotImplementedError
end

#close_on_exec?Boolean

Returns ‘true` if the close-on-exec flag is set for this stream and `false` otherwise.

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


121
122
123
# File 'lib/io/like_helpers/abstract_io.rb', line 121

def close_on_exec?
  raise NotImplementedError
end

#closed?Boolean

Returns ‘true` if this stream is closed and `false` otherwise.

Returns:

  • (Boolean)


101
102
103
# File 'lib/io/like_helpers/abstract_io.rb', line 101

def closed?
  @closed
end

#fcntl(integer_cmd, arg) ⇒ Integer

Issues low level commands to control or query the file-oriented stream upon which this stream is based.

Parameters:

  • integer_cmd (Integer)

    passed directly to ‘fcntl(2)` as an operation identifier

  • arg (Integer, String)

    passed directly to ‘fcntl(2)` if an Integer and as a binary sequence of bytes otherwise

Returns:

  • (Integer)

    the return value of ‘fcntl(2)` when not an error

Raises:

  • (IOError)

    if the stream is closed

  • (NotImplementedError)

    on platforms without the ‘fcntl(2)` function

  • (SystemCallError)

    on system level errors



139
140
141
# File 'lib/io/like_helpers/abstract_io.rb', line 139

def fcntl(integer_cmd, arg)
  raise NotImplementedError
end

#fdatasync0?

Triggers the operating system to write any buffered metadata to disk immediately.

The default implementation calls #fsync, but override this if the stream natively supports the equivalent of ‘fdatasync(2)` to offer better performance when only metadata needs to be flushed to disk.

Returns:

  • (0, nil)


152
153
154
# File 'lib/io/like_helpers/abstract_io.rb', line 152

def fdatasync
  fsync
end

#filenoInteger

Returns the numeric file descriptor for the stream.

Returns:

  • (Integer)

    the numeric file descriptor for the stream

Raises:

  • (NotImplementedError)


158
159
160
# File 'lib/io/like_helpers/abstract_io.rb', line 158

def fileno
  raise NotImplementedError
end

#fsync0?

Triggers the operating system to write any buffered data to disk immediately.

Returns:

  • (0, nil)

Raises:

  • (NotImplementedError)


167
168
169
# File 'lib/io/like_helpers/abstract_io.rb', line 167

def fsync
  raise NotImplementedError
end

#ioctl(integer_cmd, arg) ⇒ Integer

Issues low level commands to control or query the device upon which this stream is based.

Parameters:

  • integer_cmd (Integer)

    passed directly to ‘ioctl(2)` as a device dependent request code

  • arg (Integer, String)

    passed directly to ‘ioctl(2)` if an Integer and as a binary sequence of bytes otherwise

Returns:

  • (Integer)

    the return value of ‘ioctl(2)` when not an error

Raises:

  • (IOError)

    if the stream is closed

  • (NotImplementedError)

    on platforms without the ‘ioctl(2)` function

  • (SystemCallError)

    on system level errors



185
186
187
# File 'lib/io/like_helpers/abstract_io.rb', line 185

def ioctl(integer_cmd, arg)
  raise NotImplementedError
end

#nonblock(nonblock = true) {|self| ... } ⇒ self

Yields ‘self` to the given block after setting the blocking mode as dictated by `nonblock`.

Ensures that the original blocking mode is reinstated after yielding.

Parameters:

  • nonblock (Boolean) (defaults to: true)

    sets the stream to non-blocking mode if ‘true` and blocking mode otherwise

Yield Parameters:

  • self (Like)

    this stream

Returns:

  • (self)

Raises:

  • (IOError)

    if the stream is closed



203
204
205
206
207
208
209
210
211
212
# File 'lib/io/like_helpers/abstract_io.rb', line 203

def nonblock(nonblock = true)
  assert_open
  begin
    orig_nonblock = nonblock?
    self.nonblock = nonblock
    yield(self)
  ensure
    self.nonblock = orig_nonblock
  end
end

#nonblock=(nonblock) ⇒ Object

Sets the stream into either blocking or non-blocking mode.

Parameters:

  • nonblock (Boolean)

    ‘true` for non-blocking mode, `false` otherwise

Raises:

  • (IOError)

    if the stream is closed



220
221
222
# File 'lib/io/like_helpers/abstract_io.rb', line 220

def nonblock=(nonblock)
  raise NotImplementedError
end

#nonblock?true, false

Returns whether or not the stream is in non-blocking mode.

Returns:

  • (true)

    if the stream is in non-blocking mode

  • (false)

    if the stream is in blocking mode

Raises:

  • (IOError)

    if the stream is closed



231
232
233
# File 'lib/io/like_helpers/abstract_io.rb', line 231

def nonblock?
  raise NotImplementedError
end

#nreadInteger

Returns the number of bytes that can be read without blocking or ‘0` if unknown.

Returns:

  • (Integer)

    the number of bytes that can be read without blocking or ‘0` if unknown

Raises:

  • (IOError)

    if the stream is not open for reading



240
241
242
243
# File 'lib/io/like_helpers/abstract_io.rb', line 240

def nread
  assert_readable
  0
end

#pathString

Returns the path of the file associated with this stream.

Returns:

  • (String)

Raises:

  • (NotImplementedError)


249
250
251
# File 'lib/io/like_helpers/abstract_io.rb', line 249

def path
  raise NotImplementedError
end

#pidInteger?

Returns the pid of the process associated with this stream.

Returns:

  • (Integer)

    if the stream is associated with a process

  • (nil)

    if the stream is not associated with a process

Raises:

  • (IOError)

    if the stream is closed



260
261
262
263
# File 'lib/io/like_helpers/abstract_io.rb', line 260

def pid
  assert_open
  nil
end

#pread(length, offset, buffer: nil, buffer_offset: 0) ⇒ Integer, ...

Reads at most ‘length` bytes from the stream starting at `offset` without modifying the read position in the stream.

Note that a partial read will occur if the stream is in non-blocking mode and reading more bytes would block.

Parameters:

  • length (Integer)

    the maximum number of bytes to read

  • offset (Integer)

    the offset from the beginning of the stream at which to begin reading

  • buffer (String) (defaults to: nil)

    if provided, a buffer into which the bytes should be placed

  • buffer_offset (Integer) (defaults to: 0)

    the index at which to insert bytes into ‘buffer`

Returns:

  • (Integer)

    the number of bytes read if ‘buffer` is not `nil`

  • (String)

    a new String containing the bytes read if ‘buffer` is `nil` or `buffer` if provided

  • (:wait_readable, :wait_writable)

    if the stream is non-blocking and the operation would block

Raises:

  • (EOFError)

    when reading at the end of the stream

  • (IOError)

    if the stream is not readable



288
289
290
291
292
293
294
295
296
297
# File 'lib/io/like_helpers/abstract_io.rb', line 288

def pread(length, offset, buffer: nil, buffer_offset: 0)
  position = seek(0, IO::SEEK_CUR)

  seek(offset, IO::SEEK_SET)
  begin
    read(length, buffer: buffer, buffer_offset: buffer_offset)
  ensure
    seek(position, IO::SEEK_SET)
  end
end

#pwrite(buffer, offset, length: buffer.bytesize) ⇒ Integer, ...

Writes at most ‘length` bytes to the stream starting at `offset` without modifying the write position in the stream.

Note that a partial write will occur if the stream is in non-blocking mode and writing more bytes would block.

Parameters:

  • buffer (String)

    the bytes to write (encoding assumed to be binary)

  • offset (Integer)

    the offset from the beginning of the stream at which to begin writing

  • length (Integer) (defaults to: buffer.bytesize)

    the number of bytes to write from ‘buffer`

Returns:

  • (Integer)

    the number of bytes written

  • (:wait_readable, :wait_writable)

    if the stream is non-blocking and the operation would block

Raises:

  • (IOError)

    if the stream is not writable



316
317
318
319
320
321
322
323
324
325
# File 'lib/io/like_helpers/abstract_io.rb', line 316

def pwrite(buffer, offset, length: buffer.bytesize)
  position = seek(0, IO::SEEK_CUR)

  seek(offset, IO::SEEK_SET)
  begin
    write(buffer, length: length)
  ensure
    seek(position, IO::SEEK_SET)
  end
end

#read(length, buffer: nil, buffer_offset: 0) ⇒ Integer, ...

Reads bytes from the stream.

Note that a partial read will occur if the stream is in non-blocking mode and reading more bytes would block.

Parameters:

  • length (Integer)

    the number of bytes to read

  • buffer (String) (defaults to: nil)

    the buffer into which bytes will be read (encoding assumed to be binary)

  • buffer_offset (Integer) (defaults to: 0)

    the index at which to insert bytes into ‘buffer`

Returns:

  • (Integer)

    the number of bytes read if ‘buffer` is not `nil`

  • (String)

    a buffer containing the bytes read if ‘buffer` is `nil`

  • (:wait_readable, :wait_writable)

    if the stream is non-blocking and the operation would block

Raises:

  • (EOFError)

    when reading at the end of the stream

  • (IOError)

    if the stream is not readable



346
347
348
# File 'lib/io/like_helpers/abstract_io.rb', line 346

def read(length, buffer: nil, buffer_offset: 0)
  assert_readable
end

#readable?Boolean

Returns ‘true` if the stream is readable and `false` otherwise.

Returns:

  • (Boolean)


354
355
356
# File 'lib/io/like_helpers/abstract_io.rb', line 354

def readable?
  false
end

#ready?true, false

Returns whether or not the stream has input available.

Returns:

  • (true)

    if input is available

  • (false)

    if input is not available



363
364
365
366
# File 'lib/io/like_helpers/abstract_io.rb', line 363

def ready?
  assert_open
  false
end

#seek(amount, whence) ⇒ Integer

Sets the current stream position to ‘amount` based on the setting of `whence`.

| ‘whence` | `amount` Interpretation | | ——– | ———————– | | `:CUR` or `IO::SEEK_CUR` | `amount` added to current stream position | | `:END` or `IO::SEEK_END` | `amount` added to end of stream position (`amount` will usually be negative here) | | `:SET` or `IO::SEEK_SET` | `amount` used as absolute position |

Parameters:

  • amount (Integer)

    the amount to move the position in bytes

  • whence (Integer, Symbol)

    the position alias from which to consider ‘amount`

Returns:

  • (Integer)

    the new stream position

Raises:

  • (IOError)

    if the stream is closed

  • (Errno::ESPIPE)

    if the stream is not seekable



386
387
388
389
# File 'lib/io/like_helpers/abstract_io.rb', line 386

def seek(amount, whence)
  assert_open
  raise Errno::ESPIPE
end

#statFile::Stat

Returns status information for the stream.

Returns:

  • (File::Stat)

Raises:

  • (NotImplementedError)


395
396
397
# File 'lib/io/like_helpers/abstract_io.rb', line 395

def stat
  raise NotImplementedError
end

#to_ioIO

Returns the native IO object upon which this stream is based.

Returns:

Raises:

  • (NotImplementedError)


403
404
405
# File 'lib/io/like_helpers/abstract_io.rb', line 403

def to_io
  raise NotImplementedError
end

#tty?true, false

Returns whether or not the stream is a tty.

Returns:

  • (true)

    if the stream is a tty

  • (false)

    if the stream is not a tty

Raises:

  • (IOError)

    if the stream is closed



414
415
416
417
# File 'lib/io/like_helpers/abstract_io.rb', line 414

def tty?
  assert_open
  false
end

#wait(events, timeout = nil) ⇒ true, false

Waits until the stream becomes ready for at least 1 of the specified events.

Parameters:

  • events (Integer)

    a bit mask of ‘IO::READABLE`, `IO::WRITABLE`, or `IO::PRIORITY`

  • timeout (Numeric, nil) (defaults to: nil)

    the timeout in seconds or no timeout if ‘nil`

Returns:

  • (true)

    if the stream becomes ready for at least one of the given events

  • (false)

    if the IO does not become ready before the timeout

Raises:

  • (NotImplementedError)


429
430
431
# File 'lib/io/like_helpers/abstract_io.rb', line 429

def wait(events, timeout = nil)
  raise NotImplementedError
end

#writable?Boolean

Returns ‘true` if the stream is writable and `false` otherwise.

Returns:

  • (Boolean)


455
456
457
# File 'lib/io/like_helpers/abstract_io.rb', line 455

def writable?
  false
end

#write(buffer, length: buffer.bytesize) ⇒ Integer, ...

Writes bytes to the stream.

Note that a partial write will occur if the stream is in non-blocking mode and writing more bytes would block.

Parameters:

  • buffer (String)

    the bytes to write (encoding assumed to be binary)

  • length (Integer) (defaults to: buffer.bytesize)

    the number of bytes to write from ‘buffer`

Returns:

  • (Integer)

    the number of bytes written

  • (:wait_readable, :wait_writable)

    if the stream is non-blocking and the operation would block

Raises:

  • (IOError)

    if the stream is not writable



447
448
449
# File 'lib/io/like_helpers/abstract_io.rb', line 447

def write(buffer, length: buffer.bytesize)
  assert_writable
end