Class: IO::Like

Overview

This is a wrapper class that provides the same instance methods as the IO class for simpler delegates given to it.

Constant Summary collapse

ORS =

This is used by #puts as the separator between all arguments.

"\n"

Constants included from IO::LikeHelpers::RubyFacts

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

Instance Method Summary collapse

Methods inherited from IO::LikeHelpers::DuplexedIO

#close_on_exec=, #closed?, #closed_read?, #closed_write?, #inspect, #nonblock=, #readable?, #writable?

Methods inherited from IO::LikeHelpers::DelegatedIO

#advise, #autoclose=, #autoclose?, #close_on_exec=, #close_on_exec?, create_finalizer, #fcntl, #fdatasync, #fileno, #fsync, #inspect, #ioctl, #nonblock=, #nonblock?, #path, #readable?, #ready?, #stat, #to_io, #tty?, #writable?

Methods inherited from IO::LikeHelpers::AbstractIO

#advise, #close_on_exec=, #close_on_exec?, #closed?, #fcntl, #fdatasync, #fileno, #fsync, #ioctl, #nonblock, #nonblock=, #nonblock?, open, #path, #readable?, #ready?, #stat, #to_io, #tty?, #writable?

Constructor Details

#initialize(delegate_r, delegate_w = delegate_r, autoclose: true, binmode: false, encoding: nil, encoding_opts: {}, external_encoding: nil, internal_encoding: nil, sync: false, pid: nil, pipeline_class: LikeHelpers::Pipeline) ⇒ Like

Creates a new instance of this class.

Parameters:

  • delegate_r (LikeHelpers::AbstractIO)

    delegate for read operations

  • delegate_w (LikeHelpers::AbstractIO) (defaults to: delegate_r)

    delegate for write operations

  • autoclose (Boolean) (defaults to: true)

    when ‘true` close the delegate(s) when this stream is closed

  • binmode (Boolean) (defaults to: false)

    when ‘true` suppresses EOL <-> CRLF conversion on Windows and sets external encoding to ASCII-8BIT unless explicitly specified

  • encoding (Encoding, String) (defaults to: nil)

    the external encoding or both the external and internal encoding if specified as ‘“ext_enc:int_enc”`

  • encoding_opts (Hash) (defaults to: {})

    options to be passed to String#encode

  • external_encoding (Encoding, String) (defaults to: nil)

    the external encoding

  • internal_encoding (Encoding, String) (defaults to: nil)

    the internal encoding

  • sync (Boolean) (defaults to: false)

    when ‘true` causes write operations to bypass internal buffering

  • pid (Integer) (defaults to: nil)

    the return value for #pid



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/io/like.rb', line 43

def initialize(
  delegate_r,
  delegate_w = delegate_r,
  autoclose: true,
  binmode: false,
  encoding: nil,
  encoding_opts: {},
  external_encoding: nil,
  internal_encoding: nil,
  sync: false,
  pid: nil,
  pipeline_class: LikeHelpers::Pipeline
)
  if encoding
    if external_encoding
      warn("Ignoring encoding parameter '#{encoding}': external_encoding is used")
      encoding = nil
    elsif internal_encoding
      warn("Ignoring encoding parameter '#{encoding}': internal_encoding is used")
      encoding = nil
    end
  end

  if external_encoding
    external_encoding = Encoding.find(external_encoding)
  elsif internal_encoding
    external_encoding = Encoding.default_external
  end

  @pipeline_class = pipeline_class
  pipeline_r = @pipeline_class.new(delegate_r, autoclose: autoclose)
  pipeline_w = delegate_r == delegate_w ?
    pipeline_r :
    @pipeline_class.new(delegate_w, autoclose: autoclose)

  super(pipeline_r, pipeline_w)

  # NOTE:
  # Binary mode must be set before the encoding in order to allow any
  # explicitly set external encoding to override the implicit ASCII-8BIT
  # encoding when binmode is set.
  @binmode = false
  self.binmode if binmode
  if ! binmode || encoding || external_encoding || internal_encoding
    if encoding && ! (Encoding === encoding) && encoding =~ /^bom\|/i
      if ! set_encoding_by_bom
        set_encoding(encoding.to_s[4..-1], **encoding_opts)
      end
    else
      set_encoding(
        encoding || external_encoding, internal_encoding, **encoding_opts
      )
    end
  end

  @pid = nil == pid ? pid : ensure_integer(pid)

  self.sync = sync

  @skip_duplexed_check = false
  @readable = @writable = nil
end

Instance Method Details

#<<(obj) ⇒ self

Writes ‘obj` to the stream using #write.

Parameters:

  • obj

    converted to a String using its #to_s method

Returns:

  • (self)


112
113
114
115
# File 'lib/io/like.rb', line 112

def <<(obj)
  write(obj)
  self
end

#binmodeself

Puts the stream into binary mode.

Once a stream is in binary mode, it cannot be reset to nonbinary mode.

  • Newline conversion disabled

  • Encoding conversion disabled

  • Content is treated as ASCII-8BIT

Returns:

  • (self)

Raises:

  • (IOError)

    if the stream is closed



128
129
130
131
132
133
# File 'lib/io/like.rb', line 128

def binmode
  assert_open
  @binmode = true
  set_encoding(Encoding::BINARY)
  self
end

#binmode?Boolean

Returns ‘true` if the stream is in binary mode and `false` otherwise.

Returns:

  • (Boolean)

Raises:

  • (IOError)

    if the stream is closed



141
142
143
144
# File 'lib/io/like.rb', line 141

def binmode?
  assert_open
  @binmode
end

#bytes(&block) ⇒ Object

Deprecated.

Use #each_byte instead.

Version:

  • < Ruby 3.0



151
152
153
154
# File 'lib/io/like.rb', line 151

def bytes(&block)
  warn('warning: IO#bytes is deprecated; use #each_byte instead')
  each_byte(&block)
end

#chars(&block) ⇒ Object

Deprecated.

Use #each_char instead.

Version:

  • < Ruby 3.0



160
161
162
163
# File 'lib/io/like.rb', line 160

def chars(&block)
  warn('warning: IO#chars is deprecated; use #each_char instead')
  each_char(&block)
end

#closenil

Closes the stream, flushing any buffered data first.

This always blocks when buffered data needs to be written, even when the stream is in nonblocking mode.

Returns:

  • (nil)


173
174
175
176
177
178
179
180
# File 'lib/io/like.rb', line 173

def close
  @skip_duplexed_check = true
  super

  nil
ensure
  @skip_duplexed_check = false
end

#close_readnil

Closes the read side of duplexed streams and closes the entire stream for read-only, non-duplexed streams.

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is non-duplexed and writable



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/io/like.rb', line 189

def close_read
  return if closed_read?

  if ! @skip_duplexed_check && ! duplexed? && writable?
    raise IOError, 'closing non-duplex IO for reading'
  end

  super

  nil
end

#close_writenil

Closes the write side of duplexed streams and closes the entire stream for write-only, non-duplexed streams.

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is non-duplexed and readable



208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/io/like.rb', line 208

def close_write
  return if closed_write?

  if ! @skip_duplexed_check && ! duplexed? && readable?
    raise IOError, 'closing non-duplex IO for writing'
  end

  flush if writable?
  super

  nil
end

#codepoints(&block) ⇒ Object

Deprecated.

Use #each_codepoint instead.

Version:

  • < Ruby 3.0



226
227
228
229
# File 'lib/io/like.rb', line 226

def codepoints(&block)
  warn('warning: IO#codepoints is deprecated; use #each_codepoint instead')
  each_codepoint(&block)
end

#each_byteEnumerator #each_byte {|byte| ... } ⇒ self

Overloads:

  • #each_byteEnumerator

    Returns an enumerator that iterates over each byte in the stream.

    Returns:

    • (Enumerator)

      an enumerator that iterates over each byte in the stream

  • #each_byte {|byte| ... } ⇒ self

    Iterates over each byte in the stream, yielding each byte to the given block.

    Yield Parameters:

    • byte (Integer)

      the next byte from the stream

    Returns:

    • (self)

Raises:

  • (IOError)

    if the stream is not open for reading



246
247
248
249
250
251
252
253
# File 'lib/io/like.rb', line 246

def each_byte
  return to_enum(:each_byte) unless block_given?

  while (byte = getbyte) do
    yield(byte)
  end
  self
end

#each_charEnumerator #each_char {|char| ... } ⇒ self

Overloads:

  • #each_charEnumerator

    Returns an enumerator that iterates over each character in the stream.

    Returns:

    • (Enumerator)

      an enumerator that iterates over each character in the stream

  • #each_char {|char| ... } ⇒ self

    Iterates over each character in the stream, yielding each character to the given block.

    Yield Parameters:

    • char (String)

      the next character from the stream

    Returns:

    • (self)

Raises:

  • (IOError)

    if the stream is not open for reading



269
270
271
272
273
274
275
276
# File 'lib/io/like.rb', line 269

def each_char
  return to_enum(:each_char) unless block_given?

  while char = getc do
    yield(char)
  end
  self
end

#each_codepointEnumerator #each_codepoint {|codepoint| ... } ⇒ self

Overloads:

  • #each_codepointEnumerator

    Returns an enumerator that iterates over each Integer ordinal of each character in the stream.

    Returns:

    • (Enumerator)

      an enumerator that iterates over each Integer ordinal of each character in the stream

  • #each_codepoint {|codepoint| ... } ⇒ self

    Iterates over each Integer ordinal of each character in the stream, yielding each ordinal to the given block.

    Yield Parameters:

    • codepoint (Integer)

      the Integer ordinal of the next character from the stream

    Returns:

    • (self)

Raises:

  • (IOError)

    if the stream is not open for reading



293
294
295
296
297
298
# File 'lib/io/like.rb', line 293

def each_codepoint
  return to_enum(:each_codepoint) unless block_given?

  each_char { |c| yield(c.codepoints[0]) }
  self
end

#each_line(separator = $/, limit = nil, chomp: false) ⇒ Enumerator #each_line(limit, chomp: false) ⇒ Enumerator #each_line(separator = $/, limit = nil, chomp: false) {|line| ... } ⇒ self #each_line(limit, chomp: false) {|line| ... } ⇒ self Also known as: each

Overloads:

  • #each_line(separator = $/, limit = nil, chomp: false) ⇒ Enumerator

    Returns an enumerator that iterates over each line in the stream.

    Parameters:

    • separator (String, nil) (defaults to: $/)

      a non-empty String that separates each line, an empty String that equates to 2 or more successive newlines as the separator, or ‘nil` to indicate reading all remaining data

    • limit (Integer, nil) (defaults to: nil)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (Enumerator)

      an enumerator that iterates over each line in the stream

  • #each_line(limit, chomp: false) ⇒ Enumerator

    Returns an enumerator that iterates over each line in the stream where each line is separated by ‘$/`.

    Parameters:

    • limit (Integer)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (Enumerator)

      an enumerator that iterates over each line in the stream where each line is separated by ‘$/`

  • #each_line(separator = $/, limit = nil, chomp: false) {|line| ... } ⇒ self

    Iterates over each line in the stream, yielding each line to the given block.

    Parameters:

    • separator (String, nil) (defaults to: $/)

      a non-empty String that separates each line, an empty String that equates to 2 or more successive newlines as the separator, or ‘nil` to indicate reading all remaining data

    • limit (Integer, nil) (defaults to: nil)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Yield Parameters:

    • line (String)

      a line from the stream

    Returns:

    • (self)
  • #each_line(limit, chomp: false) {|line| ... } ⇒ self

    Iterates over each line in the stream, where each line is separated by ‘$/`, yielding each line to the given block.

    Parameters:

    • limit (Integer)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Yield Parameters:

    • line (String)

      a line from the stream

    Returns:

    • (self)

Raises:

  • (IOError)

    if the stream is not open for reading



352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/io/like.rb', line 352

def each_line(*args, **opts)
  unless block_given?
    return to_enum(:each_line, *args, **opts)
  end

  sep_string, limit = parse_readline_args(*args)
  raise ArgumentError, 'invalid limit: 0 for each_line' if limit == 0

  while (line = gets(sep_string, limit, **opts)) do
    yield(line)
  end
  self
end

#eof?Boolean Also known as: eof

Note:

This method will block if reading the stream blocks.

Note:

This method relies on buffered operations, so using it in conjuction with #sysread will be complicated at best.

Returns ‘true` if the end of the stream has been reached and `false` otherwise.

Returns:

  • (Boolean)

Raises:

  • (IOError)

    if the stream is not open for reading



378
379
380
381
382
383
384
# File 'lib/io/like.rb', line 378

def eof?
  if byte = getbyte
    ungetbyte(byte)
    return false
  end
  true
end

#external_encodingEncoding?

Returns the external encoding of the stream, if any.

Returns:

  • (Encoding)

    the Encoding object that represents the encoding of the stream

  • (nil)

    if the stream is writable and no encoding is specified

Raises:

  • (IOError)

    if the stream is closed and Ruby version is less than 3.1



395
396
397
398
399
400
401
402
# File 'lib/io/like.rb', line 395

def external_encoding
  assert_open if RBVER_LT_3_1

  encoding = delegate.character_io.external_encoding
  return encoding if encoding || writable?

  Encoding::default_external
end

#flushself

Flushes the internal write buffer to the underlying stream.

Regardless of the blocking status of the stream or interruptions during writing, this method will block until either all the data is flushed or until an error is raised.

Returns:

  • (self)

Raises:

  • (IOError)

    if the stream is not open for writing



414
415
416
417
418
419
420
# File 'lib/io/like.rb', line 414

def flush
  assert_open

  delegate_w.buffered_io.flush

  self
end

#getbyteInteger?

Returns the next byte from the stream.

Returns:

  • (Integer)

    the next byte from the stream

  • (nil)

    if the end of the stream has been reached

Raises:

  • (IOError)

    if the stream is not open for reading



429
430
431
432
433
# File 'lib/io/like.rb', line 429

def getbyte
  readbyte
rescue EOFError
  return nil
end

#getcString?

Returns the next character from the stream.

Returns:

  • (String)

    the next character from the stream

  • (nil)

    if the end of the stream has been reached

Raises:

  • (IOError)

    if the stream is not open for reading



442
443
444
445
446
# File 'lib/io/like.rb', line 442

def getc
  readchar
rescue EOFError
  nil
end

#gets(separator = $/, limit = nil, chomp: false) ⇒ String? #gets(limit, chomp: false) ⇒ String?

Returns the next line from the stream.

Overloads:

  • #gets(separator = $/, limit = nil, chomp: false) ⇒ String?

    Parameters:

    • separator (String, nil) (defaults to: $/)

      a non-empty String that separates each line, an empty String that equates to 2 or more successive newlines as the separator, or ‘nil` to indicate reading all remaining data

    • limit (Integer, nil) (defaults to: nil)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (String)

      the next line in the stream

    • (nil)

      if the end of the stream has been reached

  • #gets(limit, chomp: false) ⇒ String?

    Parameters:

    • limit (Integer)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (String)

      the next line in the stream where the separator is ‘$/`

    • (nil)

      if the end of the stream has been reached

Raises:

  • (IOError)

    if the stream is not open for reading



475
476
477
478
479
480
481
482
483
# File 'lib/io/like.rb', line 475

def gets(*args, **opts)
  readline(*args, **opts)
rescue EOFError
  # NOTE:
  # Through Ruby 3.3, assigning to $_ has no effect outside of a method that
  # does it.  This assignment is kept in case that ever changes.
  $_ = nil
  nil
end

#internal_encodingEncoding?

Returns the internal encoding of the stream, if any.

Returns:

  • (Encoding)

    the Encoding object that represents the encoding of the internal string conversion

  • (nil)

    if no encoding is specified

Raises:

  • (IOError)

    if the stream is closed and Ruby version is less than 3.1



493
494
495
496
# File 'lib/io/like.rb', line 493

def internal_encoding
  assert_open if RBVER_LT_3_1
  delegate.character_io.internal_encoding
end

#linenoInteger

Returns the current line number of the stream.

More accurately the number of times #gets is called on the stream and returns a non-‘nil` result, either explicitly or implicitly via methods such as #each_line, #readline, #readlines, etc. is returned. This may differ from the number of lines if `$/` is changed from the default or if #gets is called with a different separator.

Returns:

  • (Integer)

    the current line number of the stream

Raises:

  • (IOError)

    if the stream is not open for reading



514
515
516
517
518
# File 'lib/io/like.rb', line 514

def lineno
  assert_readable

  @lineno ||= 0
end

#lineno=(integer) ⇒ Integer

Sets the current line number of the stream 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 the `Integer` method.

Returns:

  • (Integer)

    the current line number of the stream

Raises:

  • (IOError)

    if the stream is not open for reading



528
529
530
531
532
# File 'lib/io/like.rb', line 528

def lineno=(integer)
  assert_readable

  @lineno = ensure_integer(integer)
end

#lines(*args, &block) ⇒ Object

Deprecated.

Use #each_line instead.

Version:

  • < Ruby 3.0



539
540
541
542
# File 'lib/io/like.rb', line 539

def lines(*args, &block)
  warn('warning: IO#lines is deprecated; use #each_line instead')
  each_line(*args, &block)
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



550
551
552
553
554
555
556
557
# File 'lib/io/like.rb', line 550

def nread
  assert_readable

  unless delegate_r.character_io.buffer_empty?
    raise IOError, 'byte oriented read for character buffered IO'
  end
  delegate_r.nread
end

#pidInteger?

Returns the process ID of a child process associated with this stream, if any.

Returns:

  • (Integer)

    a process ID

  • (nil)

    if there is no associated child process

Raises:

  • (IOError)

    if the stream is closed



567
568
569
570
571
# File 'lib/io/like.rb', line 567

def pid
  assert_open
  return @pid unless nil == @pid
  super
end

#posInteger Also known as: tell

Note:

This method will block if writing the stream blocks and there is data in the write buffer.

Returns the current byte offset of the stream.

Returns:

  • (Integer)

    the current byte offset of the stream

Raises:

  • (IOError)

    if the stream is closed

  • (Errno::ESPIPE)

    if the stream is not seekable



581
582
583
584
585
586
# File 'lib/io/like.rb', line 581

def pos
  assert_open

  flush
  delegate.seek(0, IO::SEEK_CUR)
end

#pos=(position) ⇒ Integer

Sets the position of the stream to the given byte offset.

Parameters:

  • position (Integer)

    the byte offset to which the stream will be set

Returns:

  • (Integer)

    the given byte offset

Raises:

  • (IOError)

    if the stream is closed

  • (Errno::ESPIPE)

    if the stream is not seekable



598
599
600
601
# File 'lib/io/like.rb', line 598

def pos=(position)
  seek(position, IO::SEEK_SET)
  position
end

#pread(maxlen, offset, buffer = nil) ⇒ String

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

Parameters:

  • maxlen (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

Returns:

  • (String)

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

Raises:

  • (EOFError)

    when reading at the end of the stream

  • (IOError)

    if the stream is not readable



618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
# File 'lib/io/like.rb', line 618

def pread(maxlen, offset, buffer = nil)
  maxlen = ensure_integer(maxlen)
  raise ArgumentError, 'negative string size (or size too big)' if maxlen < 0
  buffer = nil == buffer ? ''.b : ensure_string(buffer)

  return buffer if maxlen == 0

  offset = ensure_integer(offset)
  raise Errno::EINVAL if offset < 0

  assert_readable

  if maxlen > buffer.bytesize
    buffer << "\0" * (maxlen - buffer.bytesize)
  end
  bytes_read = delegate_r.pread(maxlen, offset, buffer: buffer)
  buffer.slice!(bytes_read..-1)

  buffer
end

Writes the given object(s), if any, to the stream using #write.

If no objects are given, ‘$_` is written. 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`.

Parameters:

  • args (Array<Object>)

    zero or more objects to write to the stream

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is not open for writing



651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
# File 'lib/io/like.rb', line 651

def print(*args)
  # NOTE:
  # Through Ruby 3.1, $_ is always nil on entry to a Ruby method.  This
  # assignment is kept in case that ever changes.
  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
      first_arg = false
    else
      write($,)
    end

    write(arg)
  end

  # Write the output record separator if one is specified.
  write($\) if $\
  nil
end

#printf(*args) ⇒ nil

Writes the String returned by calling ‘Kernel.sprintf` using the given arguments.

Parameters:

  • args (Array)

    arguments to pass to ‘Kernel.sprintf`

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is not open for writing



683
684
685
686
# File 'lib/io/like.rb', line 683

def printf(*args)
  write(sprintf(*args))
  nil
end

#putc(obj) ⇒ obj

If ‘obj` is a String, write the first character; otherwise, convert `obj` to an Integer using the `Integer` method and write the low order byte.

Parameters:

  • obj (String, Numeric)

    the character to be written

Returns:

  • (obj)

    the given parameter

Raises:

  • (TypeError)

    if ‘obj` is not a String nor convertable to a Numeric type

  • (IOError)

    if the stream is not open for writing



699
700
701
702
703
704
705
706
707
708
# File 'lib/io/like.rb', line 699

def putc(obj)
  char = case obj
         when String
           obj[0]
         else
           [ensure_integer(obj)].pack('V')[0]
         end
  write(char)
  obj
end

#puts(*args) ⇒ nil

Writes the given object(s), if any, to the stream.

Uses #write after converting objects to strings using their ‘to_s` methods. Unlike #print, Array instances are recursively processed. The 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.

Parameters:

  • args (Array<Object>)

    zero or more objects to write to the stream

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is not open for writing



725
726
727
728
729
730
731
732
733
734
# File 'lib/io/like.rb', line 725

def puts(*args)
  # Write only the record separator if no arguments are given.
  if args.length == 0
    write(ORS)
    return
  end

  flatten_puts(args)
  nil
end

#pwrite(string, offset) ⇒ Integer

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

Parameters:

  • string (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

Returns:

  • (Integer)

    the number of bytes written

Raises:

  • (IOError)

    if the stream is not writable



747
748
749
750
751
752
753
754
755
756
# File 'lib/io/like.rb', line 747

def pwrite(string, offset)
  string = string.to_s

  offset = ensure_integer(offset)
  raise Errno::EINVAL if offset < 0

  assert_writable

  delegate_w.pwrite(string, offset)
end

#read(length = nil, buffer = nil) ⇒ String?

Reads data from the stream.

If ‘length` is specified as 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.

Parameters:

  • length (Integer) (defaults to: nil)

    the number of bytes to read

  • buffer (String) (defaults to: nil)

    the location into which data will be stored

Returns:

  • (String)

    the data read from the stream

  • (nil)

    if ‘length` is non-zero but no data is left in the stream

Raises:

  • (ArgumentError)

    if ‘length` is less than 0

  • (IOError)

    if the stream is not open for reading



783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
# File 'lib/io/like.rb', line 783

def read(length = nil, buffer = nil)
  length = ensure_integer(length) if nil != length
  if nil != length && length < 0
    raise ArgumentError, "negative length #{length} given"
  end
  buffer = ensure_string(buffer) unless nil == buffer

  assert_readable

  unless length
    content = begin
                delegate_r.character_io.read_all
              rescue EOFError
                ''.encode(
                  internal_encoding ||
                  external_encoding ||
                  Encoding.default_external
                )
              end
    return content unless buffer
    return buffer.replace(content)
  end

  unless delegate_r.character_io.buffer_empty?
    raise IOError, 'byte oriented read for character buffered IO'
  end

  content = read_bytes(length)
  if buffer
    orig_encoding = buffer.encoding
    buffer.replace(content)
    buffer.force_encoding(orig_encoding)
    content = buffer
  end

  return nil if content.empty? && length > 0
  return content
end

#read_nonblock(length, buffer = nil, exception: true) ⇒ String, ...

Reads and returns at most ‘length` bytes from the stream.

If the internal read buffer is not empty, only the buffer is used, even if less than ‘length` bytes are available. If the internal buffer is empty, sets non-blocking mode via IO::LikeHelpers::DuplexedIO#nonblock= and then reads from the underlying stream.

Parameters:

  • length (Integer)

    the number of bytes to read

  • buffer (String) (defaults to: nil)

    the location in which to store the data

  • exception (Boolean) (defaults to: true)

    when ‘true` causes this method to raise exceptions when no data is available; otherwise, symbols are returned

Returns:

  • (String)

    the data read from the stream

  • (:wait_readable, :wait_writable)

    if ‘exception` is `false` and no data is available

  • (nil)

    if ‘exception` is `false` and reading begins at the end of the stream

Raises:

  • (EOFError)

    if reading begins at the end of the stream

  • (IOError)

    if the stream is not open for reading

  • (IO::EWOULDBLOCKWaitReadable, IO::EWOULDBLOCKWaitWritable)

    if ‘exception` is `true` and no data is available

  • (Errno::EBADF)

    if non-blocking mode is not supported

  • (SystemCallError)

    if there are low level errors



847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
# File 'lib/io/like.rb', line 847

def read_nonblock(length, buffer = nil, exception: true)
  length = ensure_integer(length)
  raise ArgumentError, 'length must be at least 0' if length < 0
  buffer = ensure_string(buffer) if nil != buffer

  assert_readable

  if RBVER_LT_3_0_4 && length == 0
    return (buffer || ''.b)
  end

  unless delegate_r.character_io.buffer_empty?
    raise IOError, 'byte oriented read for character buffered IO'
  end

  result = ensure_buffer(length, buffer) do |binary_buffer|
    unless delegate_r.buffered_io.read_buffer_empty?
      next delegate_r.read(length, buffer: binary_buffer)
    end

    self.nonblock = true
    delegate_r.concrete_io.read(length, buffer: binary_buffer)
  end

  case result
  when String
    # This means that a buffer was not given and that the delegate returned a
    # buffer with the content.
    return result
  when Integer
    # This means that a buffer was given and that the content is in the
    # buffer.
    return buffer
  else
    return nonblock_response(result, exception)
  end
rescue EOFError
  raise if exception
  return nil
end

#readbyteInteger

Returns the next 8-bit byte (0..255) from the stream.

Returns:

  • (Integer)

    the next 8-bit byte (0..255) from the stream

Raises:

  • (EOFError)

    if reading begins at the end of the stream

  • (IOError)

    if the stream is not open for reading



893
894
895
896
897
898
899
900
901
# File 'lib/io/like.rb', line 893

def readbyte
  assert_readable

  unless delegate_r.character_io.buffer_empty?
    raise IOError, 'byte oriented read for character buffered IO'
  end
  byte = delegate_r.read(1)
  byte[0].ord
end

#readcharString

Returns the next character from the stream.

Returns:

  • (String)

    the next character from the stream

Raises:

  • (EOFError)

    if reading begins at the end of the stream

  • (IOError)

    if the stream is not open for reading



908
909
910
911
912
# File 'lib/io/like.rb', line 908

def readchar
  assert_readable

  delegate_r.character_io.read_char
end

#readline(separator = $/, limit = nil, chomp: false) ⇒ String #readline(limit, chomp: false) ⇒ String

Returns the next line from the stream.

Overloads:

  • #readline(separator = $/, limit = nil, chomp: false) ⇒ String

    Returns the next line in the stream.

    Parameters:

    • separator (String, nil) (defaults to: $/)

      a non-empty String that separates each line, an empty String that equates to 2 or more successive newlines as the separator, or ‘nil` to indicate reading all remaining data

    • limit (Integer, nil) (defaults to: nil)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (String)

      the next line in the stream

  • #readline(limit, chomp: false) ⇒ String

    Returns the next line in the stream where the separator is ‘$/`.

    Parameters:

    • limit (Integer)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (String)

      the next line in the stream where the separator is ‘$/`

Raises:

  • (EOFError)

    if reading begins at the end of the stream

  • (IOError)

    if the stream is not open for reading



940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
# File 'lib/io/like.rb', line 940

def readline(*args, **opts)
  separator, limit = parse_readline_args(*args)
  chomp = opts.fetch(:chomp, false)

  assert_readable

  discard_newlines = false
  encoding =
    internal_encoding || external_encoding || Encoding.default_external

  if separator
    # Reading with a record separator is performed using bytes rather than
    # characters, so ensure that the separator is correctly encoded to make
    # this possible.
    if separator.empty?
      # Read by paragraph is requested.  The separator is 2 newline characters
      # in the encoding of the character reader.
      discard_newlines = true
      separator = "\n\n"
      separator = separator.b if RBVER_LT_3_4
    elsif $/.equal?(separator)
      # When using the default record separator character, convert it into the
      # encoding of the character reader.
      separator = separator.encode(encoding)
    elsif ! (separator.encoding == encoding ||
             (separator.ascii_only? && encoding.ascii_compatible?))
      # Raise an error when the separator encoding doesn't match the reader
      # encoding and ASCII compatibility is not available.
      #
      # NOTE:
      # We should probably attempt to convert the encoding of the separator
      # into the encoding of the reader before raising this error, but MRI
      # doesn't appear to do that.
      raise ArgumentError,
        'encoding mismatch: %s IO with %s RS' % [encoding, separator.encoding]
    end
  end

  buffer = delegate_r.character_io.read_line(
    separator: separator,
    limit: limit,
    chomp: chomp,
    discard_newlines: discard_newlines
  )

  # Increment the number of times this method has returned a "line".
  self.lineno += 1
  # Set the last line number in the global.
  $. = lineno
  # Set the last read line in the global and return it.
  # NOTE:
  # Through Ruby 3.3, assigning to $_ has no effect outside of a method that
  # does it.  This assignment is kept in case that ever changes.
  $_ = buffer
end

#readlines(separator = $/, limit = nil, chomp: false) ⇒ Array<String> #readlines(limit, chomp: false) ⇒ Array<String>

Overloads:

  • #readlines(separator = $/, limit = nil, chomp: false) ⇒ Array<String>

    Returns the remaining lines in the stream.

    Parameters:

    • separator (String, nil) (defaults to: $/)

      a non-empty String that separates each line, an empty String that equates to 2 or more successive newlines as the separator, or ‘nil` to indicate reading all remaining data

    • limit (Integer, nil) (defaults to: nil)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (Array<String>)

      the remaining lines in the stream

  • #readlines(limit, chomp: false) ⇒ Array<String>

    Returns the remaining lines in the stream where the separator is ‘$/`.

    Parameters:

    • limit (Integer)

      an Integer limiting the number of bytes returned in each line or ‘nil` to indicate no limit

    • chomp (Boolean) (defaults to: false)

      when ‘true` trailing newlines and carriage returns will be removed from each line

    Returns:

    • (Array<String>)

      the remaining lines in the stream where the separator is ‘$/`

Raises:

  • (IOError)

    if the stream is not open for reading



1020
1021
1022
# File 'lib/io/like.rb', line 1020

def readlines(*args, **opts)
  each_line(*args, **opts).to_a
end

#readpartial(length, buffer = nil) ⇒ String

Reads and returns at most ‘length` bytes from the stream.

If the internal read buffer is not empty, only the buffer is used, even if less than ‘length` bytes are available. If the internal buffer is empty, reads from the underlying stream.

Parameters:

  • length (Integer)

    the number of bytes to read

  • buffer (String) (defaults to: nil)

    the location in which to store the data

Returns:

  • (String)

    the data read from the stream

Raises:

  • (EOFError)

    if reading begins at the end of the stream

  • (IOError)

    if the stream is not open for reading



1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
# File 'lib/io/like.rb', line 1038

def readpartial(length, buffer = nil)
  length = ensure_integer(length)
  raise ArgumentError, 'length must be at least 0' if length < 0
  buffer = ensure_string(buffer) if nil != buffer

  assert_readable

  if RBVER_LT_3_0_4 && length == 0
    return (buffer || ''.b)
  end

  unless delegate_r.character_io.buffer_empty?
    raise IOError, 'byte oriented read for character buffered IO'
  end

  result = ensure_buffer(length, buffer) do |binary_buffer|
    unless delegate_r.buffered_io.read_buffer_empty?
      next delegate_r.read(length, buffer: binary_buffer)
    end

    delegate_r.blocking_io.read(length, buffer: binary_buffer)
  end

  # The delegate returns the read content unless a buffer is given.
  return nil == buffer ? result : buffer
end

#reopen(other) ⇒ self #reopen(io) ⇒ self #reopen(path, mode, **opt) ⇒ self

Replaces the delegate(s) of this stream with another instance’s delegate(s) or an IO instance.

Overloads:

  • #reopen(other) ⇒ self

    Parameters:

    • other (Like)

      another IO::Like instance whose delegate(s) will be dup’d and used as this stream’s delegate(s)

    Raises:

    • (IOError)

      if this instance is closed

  • #reopen(io) ⇒ self

    Parameters:

    • io (IO, #to_io)

      an IO instance that will be dup’d and used as this stream’s delegate

    Raises:

    • (IOError)

      if this instance or ‘io` are closed

  • #reopen(path, mode, **opt) ⇒ self

    Parameters:

    • path (String)

      path to a file to open and use as a delegate for this stream

    • mode (String)

      file open mode as used by ‘File.open`, defaults to a mode equivalent to this stream’s current read/writ-ability

    • opts (Hash)

      options hash as used by ‘File.open`

    Raises:

    • all errors raised by ‘File.open`

Returns:

  • (self)


1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
# File 'lib/io/like.rb', line 1091

def reopen(*args, **opts)
  unless args.size == 1 || args.size == 2
    raise ArgumentError,
      "wrong number of arguments (given #{args.size}, expected 1..2)"
  end

  if args.size == 1
    begin
      io = args[0]
      io = args[0].to_io unless IO::Like === io

      if IO::Like === io
        assert_open
        new_delegate_r = io.delegate_r.concrete_io.dup
        new_delegate_w = io.duplexed? ? io.delegate_w.concrete_io.dup : new_delegate_r
        close
        initialize(
          new_delegate_r,
          new_delegate_w,
          binmode: io.binmode?,
          internal_encoding: delegate_r.character_io.internal_encoding,
          external_encoding: delegate_r.character_io.external_encoding,
          sync: io.sync,
          pid: io.pid,
          pipeline_class: @pipeline_class
        )
        return self
      end

      unless IO === io
        raise TypeError,
          "can't convert #{args[0].class} to IO (#{args[0].class}#to_io gives #{io.class})"
      end

      assert_open
      io = io.dup
    rescue NoMethodError
      mode = (readable? ? 'r' : 'w').dup
      mode << '+' if readable? && writable?
      mode << 'b'
      io = File.open(args[0], mode)
    end
  else
    io = File.open(*args, **opts)
  end

  close
  initialize(
    IO::LikeHelpers::IOWrapper.new(io),
    binmode: io.binmode?,
    internal_encoding: delegate_r.character_io.internal_encoding,
    external_encoding: delegate_r.character_io.external_encoding,
    sync: io.sync,
    pid: io.pid,
    pipeline_class: @pipeline_class
  )

  self
end

#rewind0

Sets the position of the file pointer to the beginning of the stream.

The ‘lineno` attribute is reset to `0` if successful and the stream is readable.

Returns:

  • (0)

Raises:

  • (IOError)

    if the stream is closed

  • (Errno::ESPIPE)

    if the stream is not seekable



1161
1162
1163
1164
1165
# File 'lib/io/like.rb', line 1161

def rewind
  seek(0, IO::SEEK_SET)
  self.lineno = 0 if readable?
  0
end

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

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) (defaults to: IO::SEEK_SET)

    the position alias from which to consider ‘amount`

Returns:

  • (0)

Raises:

  • (IOError)

    if the stream is closed

  • (Errno::ESPIPE)

    if the stream is not seekable



1185
1186
1187
1188
1189
1190
1191
# File 'lib/io/like.rb', line 1185

def seek(amount, whence = IO::SEEK_SET)
  super
  # This also clears the byte oriented read buffer, so calling
  # delegate_r.buffered_io.flush would be redundant.
  delegate_r.character_io.clear
  0
end

#set_encoding(encoding, **opts) ⇒ self #set_encoding(external, internal, **opts) ⇒ self

Sets the external and internal encodings of the stream.

When the given external encoding is not ‘nil` or `Encoding::BINARY` or an equivalent and the internal encoding is either not given or `nil`, the current value of `Encoding.default_internal` is used for the internal encoding.

When the given external encoding is ‘nil` and the internal encoding is either not given or `nil`, the current values of `Encoding.default_external` and `Encoding.default_internal` are used, respectively, unless `Encoding.default_external` is `Encoding::BINARY` or an equivalent or `Encoding.default_internal` is `nil`, in which case `nil` is used for both.

Setting the given internal encoding to ‘“-”` indicates no character conversion should be performed. The internal encoding of the stream will be set to `nil`. This is needed in cases where `Encoding.default_internal` is not `nil` but character conversion is not desired.

Overloads:

  • #set_encoding(encoding, **opts) ⇒ self

    Parameters:

    • encoding (Encoding, String, nil)

      the external encoding or both the external and internal encoding if specified as ‘“ext_enc:int_enc”`

    • opts (Hash)

      encoding conversion options used character or newline conversion is performed

  • #set_encoding(external, internal, **opts) ⇒ self

    Parameters:

    • external (Encoding, String, nil)

      the external encoding

    • internal (Encoding, String, nil)

      the internal encoding

    • opts (Hash)

      encoding conversion options used character or newline conversion is performed

Returns:

  • (self)

Raises:

  • (TypeError)

    if the given external encoding is ‘nil` and the internal encoding is given and not `nil`

  • (ArgumentError)

    if an encoding given as a string is invalid



1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
# File 'lib/io/like.rb', line 1229

def set_encoding(ext_enc, int_enc = nil, **opts)
  assert_open

  # Check that any given newline option is valid.
  if opts.key?(:newline) &&
    ! %i{cr lf crlf universal}.include?(opts[:newline])
    message = 'unexpected value for newline option'
    message += ": #{opts[:newline]}" if Symbol === opts[:newline]
    raise ArgumentError, message
  end

  # Newline handling is not allowed in binary mode.
  if binmode? &&
    (opts.key?(:newline) ||
     opts[:cr_newline] || opts[:crlf_newline] || opts[:lf_newline] ||
     opts[:universal_newline])
    raise ArgumentError, 'newline decorator with binary mode'
  end

  # Ruby 3.2 and below have a bug (#18899) handling the internal encoding
  # correctly when the external encoding is binary that only happens when they
  # are supplied individually to this method.
  bug_18899_compatibility = RBVER_LT_3_3
  # Convert the argument(s) into Encoding objects.
  if ! (nil == ext_enc || Encoding === ext_enc) && nil == int_enc
    string_arg = ensure_string(ext_enc)
    begin
      e, _, i = string_arg.rpartition(':')
      # Bug #18899 compatibility is unnecessary when the encodings are passed
      # together as a colon speparated string.
      ext_enc, int_enc, bug_18899_compatibility = e, i, false unless e.empty?
    rescue Encoding::CompatibilityError
      # This is caused by failure to split on colon when the string argument
      # is not ASCII compatible.  Ignore it and use the argument as is.
    end
  end

  # Potential values:
  # ext_enc        int_enc
  # ======================
  # nil            Object    => error
  # nil            nil       => maybe copy default encodings
  # Object         Object    => use given encodings
  # Object         nil       => maybe copy default internal encoding
  if nil == ext_enc && nil == int_enc
    unless Encoding::BINARY == Encoding.default_external ||
           nil == Encoding.default_internal
      ext_enc = Encoding.default_external
      int_enc = Encoding.default_internal
    end
  else
    ext_enc = Encoding.find(ext_enc)
    int_enc = case int_enc
              when nil
                RBVER_LT_3_3 ? nil : Encoding.default_internal
              when '-'
                # Allows explicit request of no conversion when
                # Encoding.default_internal is set.
                nil
              else
                Encoding.find(int_enc)
              end
  end

  # Ignore the chosen internal encoding when no conversion will be performed.
  if int_enc == ext_enc ||
     Encoding::BINARY == ext_enc && ! bug_18899_compatibility
    int_enc = nil
  end

  # ASCII incompatible external encoding without conversion when reading
  # requires binmode.
  if ! binmode? && readable? && nil == int_enc &&
    ! (ext_enc || Encoding.default_external).ascii_compatible?
    raise ArgumentError, 'ASCII incompatible encoding needs binmode'
  end

  delegate_r.character_io.set_encoding(ext_enc, int_enc, **opts)
  if duplexed?
    delegate_w.character_io.set_encoding(ext_enc, int_enc, **opts)
  end

  self
end

#set_encoding_by_bomnil, Encoding

Sets the external encoding of the stream based on a byte order mark (BOM) in the next bytes of the stream if found or to ‘nil` if not found.

Returns:

  • (nil)

    if no byte order mark is found

  • (Encoding)

    the encoding indicated by the byte order mark

Raises:

  • (ArgumentError)

    if the stream is not in binary mode, an internal encoding is set, or the external encoding is set to anything other than ‘Encoding::BINARY`

Version:

  • >= Ruby 2.7



1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
# File 'lib/io/like.rb', line 1326

def set_encoding_by_bom
  unless binmode?
    raise ArgumentError, 'ASCII incompatible encoding needs binmode'
  end
  if nil != internal_encoding
    raise ArgumentError, 'encoding conversion is set'
  elsif nil != external_encoding && Encoding::BINARY != external_encoding
    raise ArgumentError, "encoding is set to #{external_encoding} already"
  end

  return nil unless readable?

  case b1 = getbyte
  when nil
  when 0xEF
    case b2 = getbyte
    when nil
    when 0xBB
      case b3 = getbyte
      when nil
      when 0xBF
        set_encoding(Encoding::UTF_8)
        return Encoding::UTF_8
      end
      ungetbyte(b3)
    end
    ungetbyte(b2)
  when 0xFE
    case b2 = getbyte
    when nil
    when 0xFF
      set_encoding(Encoding::UTF_16BE)
      return Encoding::UTF_16BE
    end
    ungetbyte(b2)
  when 0xFF
    case b2 = getbyte
    when nil
    when 0xFE
      case b3 = getbyte
      when nil
      when 0x00
        case b4 = getbyte
        when nil
        when 0x00
          set_encoding(Encoding::UTF_32LE)
          return Encoding::UTF_32LE
        end
        ungetbyte(b4)
      end
      ungetbyte(b3)
      set_encoding(Encoding::UTF_16LE)
      return Encoding::UTF_16LE
    end
    ungetbyte(b2)
  when 0x00
    case b2 = getbyte
    when nil
    when 0x00
      case b3 = getbyte
      when nil
      when 0xFE
        case b4 = getbyte
        when nil
        when 0xFF
          set_encoding(Encoding::UTF_32BE)
          return Encoding::UTF_32BE
        end
        ungetbyte(b4)
      end
      ungetbyte(b3)
    end
    ungetbyte(b2)
  end
  ungetbyte(b1)

  return nil
end

#syncBoolean

Returns ‘true` if the internal write buffer is being bypassed and `false` otherwise.

Returns:

  • (Boolean)

Raises:

  • (IOError)

    if the stream is closed



1412
1413
1414
1415
# File 'lib/io/like.rb', line 1412

def sync
  assert_open
  delegate_w.character_io.sync?
end

#sync=(sync) ⇒ 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.

Parameters:

  • sync (Boolean)

    the sync mode

Returns:

  • (Boolean)

    the given value for ‘sync`

Raises:

  • (IOError)

    if the stream is closed



1427
1428
1429
1430
# File 'lib/io/like.rb', line 1427

def sync=(sync)
  assert_open
  delegate_w.character_io.sync = sync
end

#sysread(length, buffer = nil) ⇒ String

Reads and returns up to ‘length` bytes directly from the data stream, bypassing the internal read buffer.

If ‘buffer` is given, it is used to store the bytes that are read; otherwise, a new buffer is created.

Returns an empty String if ‘length` is `0` regardless of the status of the data stream. This is for compatibility with `IO#sysread`.

Parameters:

  • length (Integer)

    the number of bytes to read

  • buffer (String) (defaults to: nil)

    a buffer into which bytes will be read

Returns:

  • (String)

    the bytes that were read

Raises:

  • (EOFError)

    if reading begins at the end of the stream

  • (IOError)

    if the internal read buffer is not empty

  • (IOError)

    if the stream is not open for reading



1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
# File 'lib/io/like.rb', line 1450

def sysread(length, buffer = nil)
  length = ensure_integer(length)
  raise ArgumentError, "negative length #{length} given" if length < 0
  buffer = ensure_string(buffer) unless nil == buffer

  return (buffer || ''.b) if length == 0

  assert_readable

  if ! delegate_r.buffered_io.read_buffer_empty?
    raise IOError, 'sysread for buffered IO'
  elsif ! delegate_r.character_io.buffer_empty?
    raise IOError, 'byte oriented read for character buffered IO'
  end

  result = ensure_buffer(length, buffer) do |binary_buffer|
    delegate_r.blocking_io.read(length, buffer: binary_buffer)
  end

  # The delegate returns the read content unless a buffer is given.
  return buffer ? buffer : result
end

#sysseek(offset, 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:

  • offset (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 internal read buffer is not empty

  • (IOError)

    if the stream is closed

  • (Errno::ESPIPE)

    if the stream is not seekable



1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
# File 'lib/io/like.rb', line 1492

def sysseek(offset, whence = IO::SEEK_SET)
  assert_open
  if ! delegate_r.buffered_io.read_buffer_empty? ||
     ! delegate_r.character_io.buffer_empty?
    raise IOError, 'sysseek for buffered IO'
  end
  unless delegate_w.buffered_io.write_buffer_empty?
    warn('warning: sysseek for buffered IO')
  end

  delegate.blocking_io.seek(offset, whence)
end

#syswrite(string) ⇒ Integer

Writes ‘string` directly to the data stream, bypassing the internal write buffer.

Parameters:

  • string (String)

    a string of bytes to be written

Returns:

  • (Integer)

    the number of bytes written

Raises:

  • (IOError)

    if the stream is not open for writing



1514
1515
1516
1517
1518
1519
1520
1521
# File 'lib/io/like.rb', line 1514

def syswrite(string)
  assert_writable
  unless delegate_w.buffered_io.write_buffer_empty?
    warn('warning: syswrite for buffered IO')
  end

  delegate_w.buffered_io.flush || delegate_w.blocking_io.write(string.to_s.b)
end

#ungetbyte(string) ⇒ nil #ungetbyte(integer) ⇒ nil

Pushes bytes onto the internal read buffer such that subsequent read operations will return them first.

Overloads:

  • #ungetbyte(string) ⇒ nil

    Parameters:

    • string (String)

      a string of bytes to push onto the internal read buffer

  • #ungetbyte(integer) ⇒ nil

    Parameters:

    • integer (Integer)

      a number whose low order byte will be pushed onto the internal read buffer

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is not open for reading

  • (IOError)

    if the internal read buffer does not have enough space



1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
# File 'lib/io/like.rb', line 1543

def ungetbyte(obj)
  assert_readable

  return if nil == obj

  string = case obj
           when String
             obj
           when Integer
             (obj & 255).chr
           else
             ensure_string(obj)
           end

  delegate_r.character_io.unread(string.b)

  nil
end

#ungetc(string) ⇒ nil #ungetc(integer) ⇒ nil

Pushes characters onto the internal read buffer such that subsequent read operations will return them first.

Overloads:

  • #ungetc(string) ⇒ nil

    Parameters:

    • string (String)

      a string of characters to push onto the internal read buffer

  • #ungetc(integer) ⇒ nil

    Parameters:

    • integer (Integer)

      a number that will be converted into a character using the stream’s external encoding and pushed onto the internal read buffer

Returns:

  • (nil)

Raises:

  • (IOError)

    if the stream is not open for reading

  • (IOError)

    if the internal read buffer does not have enough space



1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
# File 'lib/io/like.rb', line 1579

def ungetc(string)
  assert_readable

  return if nil == string && RBVER_LT_3_0

  string = case string
           when String
             string.dup
           when Integer
             encoding = internal_encoding || external_encoding
             nil == encoding ? string.chr : string.chr(encoding)
           else
             ensure_string(string)
           end

  delegate_r.character_io.unread(string.b)

  nil
end

#wait(events, timeout) ⇒ self? #wait(timeout = nil, mode = :read) ⇒ self?

Overloads:

  • #wait(events, timeout) ⇒ self?

    Parameters:

    • events (Integer)

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

    • timeout (Numeric, nil)

      the timeout in seconds or no timeout if ‘nil`

  • #wait(timeout = nil, mode = :read) ⇒ self?
    Deprecated.

    Included for compability with Ruby 2.7 and earlier

    Parameters:

    • timeout (Numeric) (defaults to: nil)
    • mode (Symbol) (defaults to: :read)

Returns:

  • (self)

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

  • (nil)

    if the IO does not become ready before the timeout

Raises:

  • (IOError)

    if the stream is closed



1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
# File 'lib/io/like.rb', line 1617

def wait(*args)
  events = 0
  timeout = nil
  if RBVER_LT_3_0
    # Ruby <=2.7 compatibility mode while running Ruby <=2.7.
    args.each do |arg|
      case arg
      when Symbol
        events |= wait_event_from_symbol(arg)
      else
        timeout = arg
        if nil != timeout && timeout < 0
          raise ArgumentError, 'time interval must not be negative'
        end
      end
    end
  else
    if args.size < 2 || args.size >= 2 && Symbol === args[1]
      # Ruby <=2.7 compatibility mode while running Ruby >=3.0.
      timeout = args[0] if args.size > 0
      if nil != timeout && timeout < 0
        raise ArgumentError, 'time interval must not be negative'
      end
      events = args[1..-1]
        .map { |mode| wait_event_from_symbol(mode) }
        .inject(0) { |memo, value| memo | value }
    elsif args.size == 2
      # Ruby >=3.0 mode.
      events = ensure_integer(args[0])
      timeout = args[1]
      if nil != timeout && timeout < 0
        raise ArgumentError, 'time interval must not be negative'
      end
    else
      # Arguments are invalid, but punt like Ruby 3.0 does.
      return nil
    end
  end
  events = IO::READABLE if events == 0

  assert_open

  return self if super(events, timeout)
  return nil
end

#wait_priority(timeout = nil) ⇒ self?

Waits until the stream is priority or until ‘timeout` is reached.

Returns ‘true` immediately if buffered data is available to read.

Returns:

  • (self)

    when the stream is priority

  • (nil)

    when the call times out

Raises:

  • (IOError)

    if the stream is not open for reading

Version:

  • >= Ruby 3.0



1675
1676
1677
1678
1679
1680
# File 'lib/io/like.rb', line 1675

def wait_priority(timeout = nil)
  assert_readable

  return self if delegate.wait(IO::PRIORITY, timeout)
  return nil
end

#wait_readable(timeout = nil) ⇒ self?

Waits until the stream is readable or until ‘timeout` is reached.

Returns ‘true` immediately if buffered data is available to read.

Returns:

  • (self)

    when the stream is readable

  • (nil)

    when the call times out

Raises:

  • (IOError)

    if the stream is not open for reading



1692
1693
1694
1695
1696
1697
# File 'lib/io/like.rb', line 1692

def wait_readable(timeout = nil)
  assert_readable

  return self if delegate.wait(IO::READABLE, timeout)
  return nil
end

#wait_writable(timeout = nil) ⇒ self?

Waits until the stream is writable or until ‘timeout` is reached.

Returns:

  • (self)

    when the stream is writable

  • (nil)

    when the call times out

Raises:

  • (IOError)

    if the stream is not open for writing



1706
1707
1708
1709
1710
1711
# File 'lib/io/like.rb', line 1706

def wait_writable(timeout = nil)
  assert_writable

  return self if delegate.wait(IO::WRITABLE, timeout)
  return nil
end

#write(*strings) ⇒ Integer

Writes the given arguments to the stream via an internal buffer and returns the number of bytes written.

If an argument is not a ‘String`, its `to_s` method is used to convert it into one. The entire contents of all arguments are written, blocking as necessary even if the underlying stream does not block.

Parameters:

  • strings (Array<Object>)

    bytes to write to the stream

Returns:

  • (Integer)

    the total number of bytes written

Raises:

  • (IOError)

    if the stream is not open for writing



1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
# File 'lib/io/like.rb', line 1726

def write(*strings)
  # This short circuit is for compatibility with old Ruby versions where this
  # method took a single argument and would return 0 when the argument
  # resulted in a 0 length string without first checking if the stream was
  # already closed.
  if strings.size == 1
    # This satisfies rubyspec by ensuring that the argument's #to_s method is
    # only called once in the case where it results in a non-empty string and
    # the short circuit is skipped.
    strings[0] = strings[0].to_s
    return 0 if strings[0].empty?
  end

  assert_writable

  delegate_w.buffered_io.flush if sync

  bytes_written = 0
  strings.each do |string|
    bytes_written += delegate_w.character_io.write(string.to_s)
  end

  bytes_written
end

#write_nonblock(string, exception: true) ⇒ Integer, ...

Enables blocking mode on the stream (via #nonblock=), flushes any buffered data, and then directly writes ‘string`, bypassing the internal buffer.

If ‘string` is not a `String`, its `to_s` method is used to convert it into one. If any of `string` is written, this method returns the number of bytes written, which may be less than all requested bytes (partial write).

Parameters:

  • string (Object)

    bytes to write to the stream

  • exception (Boolean) (defaults to: true)

    when ‘true` causes this method to raise exceptions when writing would block; otherwise, symbols are returned

Returns:

  • (Integer)

    the total number of bytes written

  • (:wait_readable, :wait_writable)

    if ‘exception` is `false` and writing to the stream would block

Raises:

  • (IOError)

    if the stream is not open for writing

  • (IO::EWOULDBLOCKWaitReadable, IO::EWOULDBLOCKWaitWritable)

    if ‘exception` is `true` and writing to the stream would block

  • (Errno::EBADF)

    if non-blocking mode is not supported

  • (SystemCallError)

    if there are low level errors



1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
# File 'lib/io/like.rb', line 1772

def write_nonblock(string, exception: true)
  assert_writable

  string = string.to_s

  self.nonblock = true
  result = delegate_w.buffered_io.flush || delegate_w.concrete_io.write(string.b)
  case result
  when Integer
    return result
  else
    return nonblock_response(result, exception)
  end
end