Class: IO::LikeHelpers::IOWrapper

Inherits:
DelegatedIO show all
Includes:
RubyFacts
Defined in:
lib/io/like_helpers/io_wrapper.rb

Overview

This class adapts Ruby’s IO implementation to the more primitive interface and behaviors expected by this library.

Constant Summary

Constants included from RubyFacts

RubyFacts::RBVER_LT_3_0, RubyFacts::RBVER_LT_3_0_4, RubyFacts::RBVER_LT_3_1, RubyFacts::RBVER_LT_3_2, RubyFacts::RBVER_LT_3_3, RubyFacts::RBVER_LT_3_4

Instance Method Summary collapse

Methods inherited from DelegatedIO

#advise, #autoclose=, #autoclose?, #close, #close_on_exec=, #close_on_exec?, create_finalizer, #fcntl, #fdatasync, #fileno, #fsync, #initialize, #inspect, #ioctl, #nonblock=, #nonblock?, #nread, #path, #pid, #stat, #to_io, #tty?

Methods inherited from AbstractIO

#advise, #close, #close_on_exec=, #close_on_exec?, #closed?, #fcntl, #fdatasync, #fileno, #fsync, #initialize, #ioctl, #nonblock, #nonblock=, #nonblock?, #nread, open, #path, #pid, #stat, #to_io, #tty?

Constructor Details

This class inherits a constructor from IO::LikeHelpers::DelegatedIO

Instance Method Details

#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



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/io/like_helpers/io_wrapper.rb', line 41

def pread(length, offset, buffer: nil, buffer_offset: 0)
  if ! buffer.nil?
    if buffer_offset < 0 || buffer_offset >= buffer.bytesize
      raise ArgumentError, 'buffer_offset is not a valid buffer index'
    end
    if buffer.bytesize - buffer_offset < length
      raise ArgumentError, 'length is greater than available buffer space'
    end
  end

  assert_readable

  content = delegate.pread(length, offset)
  return content if Symbol === content || buffer.nil?

  buffer[buffer_offset, content.bytesize] = content
  return content.bytesize
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



77
78
79
80
81
# File 'lib/io/like_helpers/io_wrapper.rb', line 77

def pwrite(buffer, offset, length: buffer.bytesize)
  assert_writable

  delegate.pwrite(buffer[0, length], offset)
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



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/io/like_helpers/io_wrapper.rb', line 102

def read(length, buffer: nil, buffer_offset: 0)
  if ! buffer.nil?
    if buffer_offset < 0 || buffer_offset >= buffer.bytesize
      raise ArgumentError, 'buffer_offset is not a valid buffer index'
    end
    if buffer.bytesize - buffer_offset < length
      raise ArgumentError, 'length is greater than available buffer space'
    end
  end

  assert_readable
  content = nonblock? ?
    read_nonblock(length) :
    delegate.sysread(length)

  return content if Symbol === content || buffer.nil?

  buffer[buffer_offset, content.bytesize] = content
  return content.bytesize
end

#readable?Boolean

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

Returns:

  • (Boolean)


127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/io/like_helpers/io_wrapper.rb', line 127

def readable?
  return false if closed?
  return @readable if defined?(@readable) && ! @readable.nil?

  @readable =
    begin
      delegate.read(0)
      true
    rescue IOError
      false
    end
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



145
146
147
148
149
# File 'lib/io/like_helpers/io_wrapper.rb', line 145

def ready?
  # This is a hack to work around the fact that IO#ready? returns an object
  # instance instead of true, contrary to documentation.
  !!super
end

#seek(amount, whence = IO::SEEK_SET) ⇒ Integer

Sets the current, unbuffered 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) (defaults to: IO::SEEK_SET)

    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



169
170
171
172
# File 'lib/io/like_helpers/io_wrapper.rb', line 169

def seek(amount, whence = IO::SEEK_SET)
  assert_open
  delegate.sysseek(amount, whence)
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



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/io/like_helpers/io_wrapper.rb', line 184

def wait(events, timeout = nil)
  # The !! is a hack to work around the fact that IO#wait returns an object
  # instance instead of true, contrary to documentation.
  return !!super unless RBVER_LT_3_0

  # The rest of this implementation is for backward compatibility with the
  # IO#wait implamentation on Ruby versions prior to 3.0.
  #
  # TODO:
  # Remove this when Ruby 2.7 and below are no longer supported by this
  # library.
  assert_open
  mode =
    case events & (IO::READABLE | IO::WRITABLE)
    when IO::READABLE | IO::WRITABLE
      :read_write
    when IO::READABLE
      :read
    when IO::WRITABLE
      :write
    else
      return false
    end
  # The !! is a hack to work around the fact that IO#wait returns an object
  # instance instead of true, contrary to documentation.
  !!delegate.wait(timeout, mode)
end

#writable?Boolean

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

Returns:

  • (Boolean)


236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/io/like_helpers/io_wrapper.rb', line 236

def writable?
  return false if closed?
  return @writable if defined?(@writable) && ! @writable.nil?

  @writable =
    begin
      delegate.write
      true
    rescue IOError
      false
    end
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



226
227
228
229
230
# File 'lib/io/like_helpers/io_wrapper.rb', line 226

def write(buffer, length: buffer.bytesize)
  assert_writable
  return delegate.syswrite(buffer[0, length]) unless nonblock?
  write_nonblock(buffer[0, length])
end