123456789_123456789_123456789_123456789_123456789_

Class: StringIO

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: ext/stringio/stringio.c

Overview

\Class \StringIO supports accessing a string as a stream, similar in some ways to class IO.

You can create a \StringIO instance using:

  • .new: returns a new \StringIO object containing the given string.
  • .open: passes a new \StringIO object to the given block.

Like an \IO stream, a \StringIO stream has certain properties:

  • Read/write mode: whether the stream may be read, written, appended to, etc.; see Read/Write Mode.
  • Data mode: text-only or binary; see Data Mode.
  • Encodings: internal and external encodings; see Encodings.
  • Position: where in the stream the next read or write is to occur; see Position.
  • Line number: a special, line-oriented, "position" (different from the position mentioned above); see Line Number.
  • Open/closed: whether the stream is open or closed, for reading or writing. see Open/Closed Streams.
  • BOM: byte mark order; see Byte Order Mark.

About the Examples

Examples on this page assume that \StringIO has been required:

require 'stringio'

And that this constant has been defined:

TEXT = <<EOT
First line
Second line

Fourth line
Fifth line
EOT

Stream Properties

Read/Write Mode

Summary

Mode Initial Clear? Read Write
'r': read-only No Anywhere Error
'w': write-only Yes Error Anywhere
'a': append-only No Error End only
'r+': read/write No Anywhere Anywhere
'w+': read-write Yes Anywhere Anywhere
'a+': read/append No Anywhere End only

Each section below describes a read/write mode.

Any of the modes may be given as a string or as file constants; example:

strio = StringIO.new('foo', 'a')
strio = StringIO.new('foo', File::WRONLY | File::APPEND)

'r': Read-Only

Mode specified as one of:

  • String: 'r'.
  • Constant: File::RDONLY.

Initial state:

strio = StringIO.new('foobarbaz', 'r')
strio.pos    # => 0            # Beginning-of-stream.
strio.string # => "foobarbaz"  # Not cleared.

May be read anywhere:

strio.gets(3) # => "foo"
strio.gets(3) # => "bar"
strio.pos = 9
strio.gets(3) # => nil

May not be written:

strio.write('foo')  # Raises IOError: not opened for writing

'w': Write-Only

Mode specified as one of:

  • String: 'w'.
  • Constant: File::WRONLY.

Initial state:

strio = StringIO.new('foo', 'w')
strio.pos    # => 0   # Beginning of stream.
strio.string # => ""  # Initially cleared.

May be written anywhere (even past end-of-stream):

strio.write('foobar')
strio.string # => "foobar"
strio.rewind
strio.write('FOO')
strio.string # => "FOObar"
strio.pos = 3
strio.write('BAR')
strio.string # => "FOOBAR"
strio.pos = 9
strio.write('baz')
strio.string # => "FOOBAR\u0000\u0000\u0000baz"  # Null-padded.

May not be read:

strio.read  # Raises IOError: not opened for reading

'a': Append-Only

Mode specified as one of:

  • String: 'a'.
  • Constant: File::WRONLY | File::APPEND.

Initial state:

strio = StringIO.new('foo', 'a')
strio.pos    # => 0      # Beginning-of-stream.
strio.string # => "foo"  # Not cleared.

May be written only at the end; position does not affect writing:

strio.write('bar')
strio.string # => "foobar"
strio.write('baz')
strio.string # => "foobarbaz"
strio.pos = 400
strio.write('bat')
strio.string # => "foobarbazbat"

May not be read:

strio.gets  # Raises IOError: not opened for reading

'r+': Read/Write

Mode specified as one of:

  • String: 'r+'.
  • Constant: File::RDRW.

Initial state:

strio = StringIO.new('foobar', 'r+')
strio.pos    # => 0         # Beginning-of-stream.
strio.string # => "foobar"  # Not cleared.

May be written anywhere (even past end-of-stream):

strio.write('FOO')
strio.string # => "FOObar"
strio.write('BAR')
strio.string # => "FOOBAR"
strio.write('BAZ')
strio.string # => "FOOBARBAZ"
strio.pos = 12
strio.write('BAT')
strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT"  # Null padded.

May be read anywhere:

strio.pos = 0
strio.gets(3) # => "FOO"
strio.pos = 6
strio.gets(3) # => "BAZ"
strio.pos = 400
strio.gets(3) # => nil

'w+': Read/Write (Initially Clear)

Mode specified as one of:

  • String: 'w+'.
  • Constant: File::RDWR | File::TRUNC.

Initial state:

strio = StringIO.new('foo', 'w+')
strio.pos    # => 0   # Beginning-of-stream.
strio.string # => ""  # Truncated.

May be written anywhere (even past end-of-stream):

strio.write('foobar')
strio.string # => "foobar"
strio.rewind
strio.write('FOO')
strio.string # => "FOObar"
strio.write('BAR')
strio.string # => "FOOBAR"
strio.write('BAZ')
strio.string # => "FOOBARBAZ"
strio.pos = 12
strio.write('BAT')
strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT"  # Null-padded.

May be read anywhere:

strio.rewind
strio.gets(3) # => "FOO"
strio.gets(3) # => "BAR"
strio.pos = 12
strio.gets(3) # => "BAT"
strio.pos = 400
strio.gets(3) # => nil

'a+': Read/Append

Mode specified as one of:

  • String: 'a+'.
  • Constant: File::RDWR | File::APPEND.

Initial state:

strio = StringIO.new('foo', 'a+')
strio.pos    # => 0      # Beginning-of-stream.
strio.string # => "foo"  # Not cleared.

May be written only at the end; #rewind; position does not affect writing:

strio.write('bar')
strio.string # => "foobar"
strio.write('baz')
strio.string # => "foobarbaz"
strio.pos = 400
strio.write('bat')
strio.string # => "foobarbazbat"

May be read anywhere:

strio.rewind
strio.gets(3) # => "foo"
strio.gets(3) # => "bar"
strio.pos = 9
strio.gets(3) # => "bat"
strio.pos = 400
strio.gets(3) # => nil

Data Mode

To specify whether the stream is to be treated as text or as binary data, either of the following may be suffixed to any of the string read/write modes above:

  • 't': Text; initializes the encoding as Encoding::UTF_8.
  • 'b': Binary; initializes the encoding as Encoding::ASCII_8BIT.

If neither is given, the stream defaults to text data.

Examples:

strio = StringIO.new('foo', 'rt')
strio.external_encoding # => #<Encoding:UTF-8>
data = "\u9990\u9991\u9992\u9993\u9994"
strio = StringIO.new(data, 'rb')
strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>

When the data mode is specified, the read/write mode may not be omitted:

StringIO.new(data, 'b')  # Raises ArgumentError: invalid access mode b

A text stream may be changed to binary by calling instance method #binmode; a binary stream may not be changed to text.

Encodings

A stream has an encoding; see Encodings.

The initial encoding for a new or re-opened stream depends on its data mode:

  • Text: Encoding::UTF_8.
  • Binary: Encoding::ASCII_8BIT.

These instance methods are relevant:

Examples:

strio = StringIO.new('foo', 'rt')  # Text mode.
strio.external_encoding # => #<Encoding:UTF-8>
data = "\u9990\u9991\u9992\u9993\u9994"
strio = StringIO.new(data, 'rb') # Binary mode.
strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>
strio = StringIO.new('foo')
strio.external_encoding # => #<Encoding:UTF-8>
strio.set_encoding('US-ASCII')
strio.external_encoding # => #<Encoding:US-ASCII>

Position

A stream has a position, and integer offset (in bytes) into the stream. The initial position of a stream is zero.

Getting and Setting the Position

Each of these methods initializes (to zero) the position of a new or re-opened stream:

  • .new: returns a new stream.
  • .open: passes a new stream to the block.
  • #reopen: re-initializes the stream.

Each of these methods queries, gets, or sets the position, without otherwise changing the stream:

  • #eof?: returns whether the position is at end-of-stream.
  • #pos: returns the position.
  • #pos=: sets the position.
  • #rewind: sets the position to zero.
  • #seek: sets the position.

Examples:

strio = StringIO.new('foobar')
strio.pos  # => 0
strio.pos = 3
strio.pos  # => 3
strio.eof? # => false
strio.rewind
strio.pos  # => 0
strio.seek(0, IO::SEEK_END)
strio.pos  # => 6
strio.eof? # => true

Position Before and After Reading

Except for #pread, a stream reading method (see Basic Reading) begins reading at the current position.

Except for #pread, a read method advances the position past the read substring.

Examples:

strio = StringIO.new(TEXT)
strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
strio.pos    # => 0
strio.getc   # => "F"
strio.pos    # => 1
strio.gets   # => "irst line\n"
strio.pos    # => 11
strio.pos = 24
strio.gets   # => "Fourth line\n"
strio.pos    # => 36

strio = StringIO.new('тест') # Four 2-byte characters.
strio.pos = 0 # At first byte of first character.
strio.read    # => "тест"
strio.pos = 1 # At second byte of first character.
strio.read    # => "\x82ест"
strio.pos = 2 # At first of second character.
strio.read    # => "ест"

strio = StringIO.new(TEXT)
strio.pos = 15
a = []
strio.each_line {|line| a.push(line) }
a         # => ["nd line\n", "\n", "Fourth line\n", "Fifth line\n"]
strio.pos # => 47  ## End-of-stream.

Position Before and After Writing

Each of these methods begins writing at the current position, and advances the position to the end of the written substring:

  • #putc: writes the given character.
  • #write: writes the given objects as strings.
  • Kernel#puts: writes given objects as strings, each followed by newline.

Examples:

strio = StringIO.new('foo')
strio.pos    # => 0
strio.putc('b')
strio.string # => "boo"
strio.pos    # => 1
strio.write('r')
strio.string # => "bro"
strio.pos    # => 2
strio.puts('ew')
strio.string # => "brew\n"
strio.pos    # => 5
strio.pos = 8
strio.write('foo')
strio.string # => "brew\n\u0000\u0000\u0000foo"
strio.pos    # => 11

Each of these methods writes before the current position, and decrements the position so that the written data is next to be read:

Examples:

strio = StringIO.new('foo')
strio.pos = 2
strio.ungetc('x')
strio.pos    # => 1
strio.string # => "fxo"
strio.ungetc('x')
strio.pos    # => 0
strio.string # => "xxo"

This method does not affect the position:

  • #truncate: truncates the stream's string to the given size.

Examples:

strio = StringIO.new('foobar')
strio.pos    # => 0
strio.truncate(3)
strio.string # => "foo"
strio.pos    # => 0
strio.pos = 500
strio.truncate(0)
strio.string # => ""
strio.pos    # => 500

Line Number

A stream has a line number, which initially is zero:

  • Method #lineno returns the line number.
  • Method #lineno= sets the line number.

The line number can be affected by reading (but never by writing); in general, the line number is incremented each time the record separator (default: "\n") is read.

Examples:

strio = StringIO.new(TEXT)
strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
strio.lineno # => 0
strio.gets   # => "First line\n"
strio.lineno # => 1
strio.getc   # => "S"
strio.lineno # => 1
strio.gets   # => "econd line\n"
strio.lineno # => 2
strio.gets   # => "\n"
strio.lineno # => 3
strio.gets   # => "Fourth line\n"
strio.lineno # => 4

Setting the position does not affect the line number:

strio.pos = 0
strio.lineno # => 4
strio.gets   # => "First line\n"
strio.pos    # => 11
strio.lineno # => 5

And setting the line number does not affect the position:

strio.lineno = 10
strio.pos    # => 11
strio.gets   # => "Second line\n"
strio.lineno # => 11
strio.pos    # => 23

Open/Closed Streams

A new stream is open for either reading or writing, and may be open for both; see Read/Write Mode.

Each of these methods initializes the read/write mode for a new or re-opened stream:

  • .new: returns a new stream.
  • .open: passes a new stream to the block.
  • #reopen: re-initializes the stream.

Other relevant methods:

  • #close: closes the stream for both reading and writing.
  • #close_read: closes the stream for reading.
  • #close_write: closes the stream for writing.
  • #closed?: returns whether the stream is closed for both reading and writing.
  • #closed_read?: returns whether the stream is closed for reading.
  • #closed_write?: returns whether the stream is closed for writing.

BOM (Byte Order Mark)

The string provided for .new, .open, or #reopen may contain an optional BOM (byte order mark) at the beginning of the string; the BOM can affect the stream's encoding.

The BOM (if provided):

  • Is stored as part of the stream's string.
  • Does not immediately affect the encoding.
  • Is initially considered part of the stream.
utf8_bom = "\xEF\xBB\xBF"
string = utf8_bom + 'foo'
string.bytes               # => [239, 187, 191, 102, 111, 111]
strio.string.bytes.take(3) # => [239, 187, 191]                  # The BOM.
strio = StringIO.new(string, 'rb')
strio.string.bytes         # => [239, 187, 191, 102, 111, 111]   # BOM is part of the stored string.
strio.external_encoding    # => #<Encoding:BINARY (ASCII-8BIT)>  # Default for a binary stream.
strio.gets                 # => "\xEF\xBB\xBFfoo"                # BOM is part of the stream.

You can call instance method #set_encoding_by_bom to "activate" the stored BOM; after doing so the BOM:

  • Is still stored as part of the stream's string.
  • Determines (and may have changed) the stream's encoding.
  • Is no longer considered part of the stream.
strio.set_encoding_by_bom
strio.string.bytes      # => [239, 187, 191, 102, 111, 111]  # BOM is still part of the stored string.
strio.external_encoding # => #<Encoding:UTF-8>               # The new encoding.
strio.rewind            # => 0
strio.gets              # => "foo"                           # BOM is not part of the stream.

Basic Stream \IO

Basic Reading

You can read from the stream using these instance methods:

  • #getbyte: reads and returns the next byte.
  • #getc: reads and returns the next character.
  • #gets: reads and returns all or part of the next line.
  • #read: reads and returns all or part of the remaining data in the stream.
  • #readlines: reads the remaining data the stream and returns an array of its lines.
  • Kernel#readline: like #gets, but raises an exception if at end-of-stream.

You can iterate over the stream using these instance methods:

  • #each_byte: reads each remaining byte, passing it to the block.
  • #each_char: reads each remaining character, passing it to the block.
  • #each_codepoint: reads each remaining codepoint, passing it to the block.
  • #each_line: reads all or part of each remaining line, passing the read string to the block

This instance method is useful in a multi-threaded application:

  • #pread: reads and returns all or part of the stream.

Basic Writing

You can write to the stream, advancing the position, using these instance methods:

  • #putc: writes a given character.
  • #write: writes the given objects as strings.
  • Kernel#puts writes given objects as strings, each followed by newline.

You can "unshift" to the stream using these instance methods; each writes before the current position, and decrements the position so that the written data is next to be read.

One more writing method:

  • #truncate: truncates the stream's string to the given size.

Line \IO

Reading:

  • #gets: reads and returns the next line.
  • Kernel#readline: like #gets, but raises an exception if at end-of-stream.
  • #readlines: reads the remaining data the stream and returns an array of its lines.
  • #each_line: reads each remaining line, passing it to the block

Writing:

  • Kernel#puts: writes given objects, each followed by newline.

Character \IO

Reading:

  • #each_char: reads each remaining character, passing it to the block.
  • #getc: reads and returns the next character.

Writing:

  • #putc: writes the given character.
  • #ungetc.: unshifts the given character.

Byte \IO

Reading:

  • #each_byte: reads each remaining byte, passing it to the block.
  • #getbyte: reads and returns the next byte.

Writing:

Codepoint \IO

Reading:

  • #each_codepoint: reads each remaining codepoint, passing it to the block.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

::IO::generic_readable - Included

#read_nonblock

Similar to #read, but raises EOFError at end of string unless the exception: false option is passed in.

#readbyte

Like #getbyte, but raises an exception if already at end-of-stream; see Byte IO.

#readchar

Like #getc, but raises an exception if already at end-of-stream; see Character IO.

#readline

Reads a line as with IO#gets, but raises EOFError if already at end-of-file; see Line IO.

#readpartial
#sysread

Similar to #read, but raises EOFError at end of string instead of returning nil, as well as IO#sysread does.

::IO::generic_writable - Included

#<<, #print, #printf, #puts, #syswrite,
#write_nonblock

See IO#write_nonblock

Constructor Details

.new(*args)

This method is for internal use only.
[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 414

static VALUE
strio_s_new(int argc, VALUE *argv, VALUE klass)
{
    if (rb_block_given_p()) {
	VALUE cname = rb_obj_as_string(klass);

	rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
		cname, cname);
    }
    return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
}

#new(string = '', mode = 'r+') ⇒ StringIO

Returns a new StringIO instance formed from #string and mode; the instance should be closed when no longer needed:

strio = StringIO.new
strio.string        # => ""
strio.closed_read?  # => false
strio.closed_write? # => false
strio.close

If #string is frozen, the default mode is 'r':

strio = StringIO.new('foo'.freeze)
strio.string        # => "foo"
strio.closed_read?  # => false
strio.closed_write? # => true
strio.close

Argument mode must be a valid Access Mode, which may be a string or an integer constant:

StringIO.new('foo', 'w+')
StringIO.new('foo', File::RDONLY)

Related: .open (passes the StringIO object to the block; closes the object automatically on block exit).

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 255

static VALUE
strio_initialize(int argc, VALUE *argv, VALUE self)
{
    struct StringIO *ptr = check_strio(self);

    if (!ptr) {
	DATA_PTR(self) = ptr = strio_alloc();
    }
    rb_call_super(0, 0);
    return strio_init(argc, argv, ptr, self);
}

Class Method Details

.open(string = '', mode = 'r+') ⇒ StringIO .open(string = '', mode = 'r+') {|strio| ... } ⇒ Object

Creates new StringIO instance by calling StringIO.new(string, mode).

With no block given, returns the new instance:

strio = StringIO.open # => #<StringIO>

With a block given, calls the block with the new instance and returns the block’s value; closes the instance on block exit:

StringIO.open('foo') {|strio| strio.string.upcase } # => "FOO"

Related: .new.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 405

static VALUE
strio_s_open(int argc, VALUE *argv, VALUE klass)
{
    VALUE obj = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
    if (!rb_block_given_p()) return obj;
    return rb_ensure(rb_yield, obj, strio_finalize, obj);
}

Instance Attribute Details

#closed?Boolean (readonly)

Returns whether self is closed for both reading and writing:

strio = StringIO.new
strio.closed?     # => false  # Open for reading and writing.
strio.close_read
strio.closed?     # => false  # Still open for writing.
strio.close_write
strio.closed?     # => true   # Now closed for both.

Related: #closed_read?, #closed_write?.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 640

static VALUE
strio_closed(VALUE self)
{
    StringIO(self);
    if (!CLOSED(self)) return Qfalse;
    return Qtrue;
}

#closed_read?Boolean (readonly)

Returns whether self is closed for reading:

strio = StringIO.new
strio.closed_read?   # => false
strio.close_read
strio.closed_read?   # => true

Related: #closed?, #closed_write?, #close_read.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 661

static VALUE
strio_closed_read(VALUE self)
{
    StringIO(self);
    if (READABLE(self)) return Qfalse;
    return Qtrue;
}

#closed_write?Boolean (readonly)

Returns whether self is closed for writing:

strio = StringIO.new
strio.closed_write? # => false
strio.close_write
strio.closed_write? # => true

Related: #close_write, #closed?, #closed_read?.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 682

static VALUE
strio_closed_write(VALUE self)
{
    StringIO(self);
    if (WRITABLE(self)) return Qfalse;
    return Qtrue;
}

#eof?Boolean (readonly) Also known as: #eof?

Returns whether self is positioned at end-of-stream:

strio = StringIO.new('foo')
strio.pos  # => 0
strio.eof? # => false
strio.read # => "foo"
strio.pos  # => 3
strio.eof? # => true
strio.close_read
strio.eof? # Raises IOError: not opened for reading

Related: #pos.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 715

static VALUE
strio_eof(VALUE self)
{
    if (strio_to_read(self)) return Qfalse;
    return Qtrue;
}

#eof?Boolean (readonly) #eof?Boolean

Alias for #eof.

#linenocurrent_line_number (rw)

Returns the current line number in self; see Line Number.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 752

static VALUE
strio_get_lineno(VALUE self)
{
    return LONG2NUM(StringIO(self)->lineno);
}

#lineno=(new_line_number) ⇒ new_line_number (rw)

Sets the current line number in self to the given new_line_number; see Line Number.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 765

static VALUE
strio_set_lineno(VALUE self, VALUE lineno)
{
    StringIO(self)->lineno = NUM2LONG(lineno);
    return lineno;
}

#posstream_position (rw)

Returns the current position (in bytes); see Position.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 840

static VALUE
strio_get_pos(VALUE self)
{
    return LONG2NUM(StringIO(self)->pos);
}

#pos=(new_position) ⇒ new_position (rw)

Sets the current position (in bytes); see Position.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 853

static VALUE
strio_set_pos(VALUE self, VALUE pos)
{
    struct StringIO *ptr = StringIO(self);
    long p = NUM2LONG(pos);
    if (p < 0) {
	error_inval(0);
    }
    ptr->pos = p;
    return pos;
}

#stringString (rw)

Returns underlying string:

StringIO.open('foo') do |strio|
  p strio.string
  strio.string = 'bar'
  p strio.string
end

Output:

"foo"
"bar"

Related: #string= (assigns the underlying string).

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 507

static VALUE
strio_get_string(VALUE self)
{
    return StringIO(self)->string;
}

#string=(other_string) ⇒ other_string (rw)

Replaces the stored string with other_string, and sets the position to zero; returns other_string:

StringIO.open('foo') do |strio|
  p strio.string
  strio.string = 'bar'
  p strio.string
end

Output:

"foo"
"bar"

Related: #string (returns the stored string).

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 533

static VALUE
strio_set_string(VALUE self, VALUE string)
{
    struct StringIO *ptr = StringIO(self);

    rb_io_taint_check(self);
    ptr->flags &= ~FMODE_READWRITE;
    StringValue(string);
    ptr->flags = readonly_string_p(string) ? FMODE_READABLE : FMODE_READWRITE;
    ptr->pos = 0;
    ptr->lineno = 0;
    RB_OBJ_WRITE(self, &ptr->string, string);
    return string;
}

#tty?Boolean (readonly)

[ GitHub ]

Instance Method Details

#binmodeself

Sets the data mode in self to binary mode; see Data Mode.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 780

static VALUE
strio_binmode(VALUE self)
{
    struct StringIO *ptr = StringIO(self);
    rb_encoding *enc = rb_ascii8bit_encoding();

    ptr->enc = enc;
    if (WRITABLE(self)) {
	rb_enc_associate(ptr->string, enc);
    }
    return self;
}

#closenil

Closes self for both reading and writing; returns nil:

strio = StringIO.new
strio.closed? # => false
strio.close   # => nil
strio.closed? # => true
strio.read    # Raises IOError: not opened for reading
strio.write   # Raises IOError: not opened for writing

Related: #close_read, #close_write, #closed?.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 563

static VALUE
strio_close(VALUE self)
{
    StringIO(self);
    RBASIC(self)->flags &= ~STRIO_READWRITE;
    return Qnil;
}

#close_readnil

Closes self for reading; closed-write setting remains unchanged; returns nil:

strio = StringIO.new
strio.closed_read?  # => false
strio.close_read    # => nil
strio.closed_read?  # => true
strio.closed_write? # => false
strio.read          # Raises IOError: not opened for reading

Related: #close, #close_write.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 588

static VALUE
strio_close_read(VALUE self)
{
    struct StringIO *ptr = StringIO(self);
    if (!(ptr->flags & FMODE_READABLE)) {
	rb_raise(rb_eIOError, "closing non-duplex IO for reading");
    }
    RBASIC(self)->flags &= ~STRIO_READABLE;
    return Qnil;
}

#close_writenil

Closes self for writing; closed-read setting remains unchanged; returns nil:

strio = StringIO.new
strio.closed_write? # => false
strio.close_write   # => nil
strio.closed_write? # => true
strio.closed_read?  # => false
strio.write('foo')  # Raises IOError: not opened for writing

Related: #close, #close_read, #closed_write?.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 614

static VALUE
strio_close_write(VALUE self)
{
    struct StringIO *ptr = StringIO(self);
    if (!(ptr->flags & FMODE_WRITABLE)) {
	rb_raise(rb_eIOError, "closing non-duplex IO for writing");
    }
    RBASIC(self)->flags &= ~STRIO_WRITABLE;
    return Qnil;
}

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

With a block given calls the block with each remaining line (see "Position" below) in the stream; returns self.

Leaves stream position at end-of-stream.

No Arguments

With no arguments given, reads lines using the default record separator (global variable $/, whose initial value is "\n").

strio = StringIO.new(TEXT)
strio.each_line {|line| p line }
strio.eof? # => true

Output:

"First line\n"
"Second line\n"
"\n"
"Fourth line\n"
"Fifth line\n"

Argument sep

With only string argument sep given, reads lines using that string as the record separator:

strio = StringIO.new(TEXT)
strio.each_line(' ') {|line| p line }

Output:

"First "
"line\nSecond "
"line\n\nFourth "
"line\nFifth "
"line\n"

Argument limit

With only integer argument limit given, reads lines using the default record separator; also limits the size (in characters) of each line to the given limit:

strio = StringIO.new(TEXT)
strio.each_line(10) {|line| p line }

Output:

"First line"
"\n"
"Second lin"
"e\n"
"\n"
"Fourth lin"
"e\n"
"Fifth line"
"\n"

Arguments sep and limit

With arguments sep and limit both given, honors both:

strio = StringIO.new(TEXT)
strio.each_line(' ', 10) {|line| p line }

Output:

"First "
"line\nSecon"
"d "
"line\n\nFour"
"th "
"line\nFifth"
" "
"line\n"

Position

As stated above, method each remaining line in the stream.

In the examples above each strio object starts with its position at beginning-of-stream; but in other cases the position may be anywhere (see #pos):

strio = StringIO.new(TEXT)
strio.pos = 30 # Set stream position to character 30.
strio.each_line {|line| p line }

Output:

" line\n"
"Fifth line\n"

In all the examples above, the stream position is at the beginning of a character; in other cases, that need not be so:

s = 'こんにちは'  # Five 3-byte characters.
strio = StringIO.new(s)
strio.pos = 3   # At beginning of second character.
strio.each_line {|line| p line }
strio.pos = 4   # At second byte of second character.
strio.each_line {|line| p line }
strio.pos = 5   # At third byte of second character.
strio.each_line {|line| p line }

Output:

"んにちは"
"\x82\x93にちは"
"\x93にちは"

Special Record Separators

Like some methods in class ::IO, #each honors two special record separators; see Special Line Separators.

strio = StringIO.new(TEXT)
strio.each_line('') {|line| p line } # Read as paragraphs (separated by blank lines).

Output:

"First line\nSecond line\n\n"
"Fourth line\nFifth line\n"
strio = StringIO.new(TEXT)
strio.each_line(nil) {|line| p line } # "Slurp"; read it all.

Output:

"First line\nSecond line\n\nFourth line\nFifth line\n"

Keyword Argument chomp

With keyword argument chomp given as true (the default is false), removes trailing newline (if any) from each line:

strio = StringIO.new(TEXT)
strio.each_line(chomp: true) {|line| p line }

Output:

"First line"
"Second line"
""
"Fourth line"
"Fifth line"

With no block given, returns a new Enumerator.

Related: #each_byte, #each_char, #each_codepoint.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1479

static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
{
    VALUE line;
    struct StringIO *ptr = readable(self);
    struct getline_arg arg;

    RETURN_ENUMERATOR(self, argc, argv);

    if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
	rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
    }

    while (!NIL_P(line = strio_getline(&arg, ptr))) {
	rb_yield(line);
    }
    return self;
}

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

With a block given, calls the block with each remaining byte in the stream; positions the stream at end-of-file; returns self:

bytes = []
strio = StringIO.new('hello')     #  Five 1-byte characters.
strio.each_byte {|byte| bytes.push(byte) }
strio.eof? # => true
bytes # => [104, 101, 108, 108, 111]
bytes = []
strio = StringIO.new('тест')      # Four 2-byte characters.
strio.each_byte {|byte| bytes.push(byte) }
bytes # => [209, 130, 208, 181, 209, 129, 209, 130]
bytes = []
strio = StringIO.new('こんにちは')  # Five 3-byte characters.
strio.each_byte {|byte| bytes.push(byte) }
bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]

The position in the stream matters:

bytes = []
strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.pos  # => 3  # 3-byte character was read.
strio.each_byte {|byte| bytes.push(byte) }
bytes      # => [227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]

If at end-of-file, does not call the block:

strio.eof? # => true
strio.each_byte {|byte| fail 'Boo!' }
strio.eof? # => true

With no block given, returns a new Enumerator.

Related: #each_char, #each_codepoint, #each_line.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 951

static VALUE
strio_each_byte(VALUE self)
{
    struct StringIO *ptr;

    RETURN_ENUMERATOR(self, 0, 0);

    while ((ptr = strio_to_read(self)) != NULL) {
	char c = RSTRING_PTR(ptr->string)[ptr->pos++];
	rb_yield(CHR2FIX(c));
    }
    return self;
}

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

With a block given, calls the block with each remaining character in the stream; positions the stream at end-of-file; returns self:

chars = []
strio = StringIO.new('hello')
strio.each_char {|char| chars.push(char) }
strio.eof? # => true
chars      # => ["h", "e", "l", "l", "o"]
chars = []
strio = StringIO.new('тест')
strio.each_char {|char| chars.push(char) }
chars      # => ["т", "е", "с", "т"]
chars = []
strio = StringIO.new('こんにちは')
strio.each_char {|char| chars.push(char) }
chars      # => ["こ", "ん", "に", "ち", "は"]

Stream position matters:

chars = []
strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.pos  # => 3  # 3-byte character was read.
strio.each_char {|char| chars.push(char) }
chars      # => ["ん", "に", "ち", "は"]

When at end-of-stream does not call the block:

strio.eof? # => true
strio.each_char {|char| fail 'Boo!' }
strio.eof? # => true

With no block given, returns a new Enumerator.

Related: #each_byte, #each_codepoint, #each_line.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1178

static VALUE
strio_each_char(VALUE self)
{
    VALUE c;

    RETURN_ENUMERATOR(self, 0, 0);

    while (!NIL_P(c = strio_getc(self))) {
	rb_yield(c);
    }
    return self;
}

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

With a block given, calls the block with each successive codepoint from self; sets the position to end-of-stream; returns self.

Each codepoint is the integer value for a character; returns self:

codepoints = []
strio = StringIO.new('hello')
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
strio.eof? # => true
codepoints # => [104, 101, 108, 108, 111]
codepoints = []
strio = StringIO.new('тест')
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
codepoints # => [1090, 1077, 1089, 1090]
codepoints = []
strio = StringIO.new('こんにちは')
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
codepoints # => [12371, 12435, 12395, 12385, 12399]

Position in the stream matters:

codepoints = []
strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.pos  # => 3
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
codepoints # => [12435, 12395, 12385, 12399]

When at end-of-stream, the block is not called:

strio.eof? # => true
strio.each_codepoint {|codepoint| fail 'Boo!' }
strio.eof? # => true

With no block given, returns a new Enumerator.

Related: #each_byte, #each_char, #each_line.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1199

static VALUE
strio_each_codepoint(VALUE self)
{
    struct StringIO *ptr;
    rb_encoding *enc;
    unsigned int c;
    int n;

    RETURN_ENUMERATOR(self, 0, 0);

    ptr = readable(self);
    enc = get_enc(ptr);
    while ((ptr = strio_to_read(self)) != NULL) {
	c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
				 RSTRING_END(ptr->string), &n, enc);
	ptr->pos += n;
	rb_yield(UINT2NUM(c));
    }
    return self;
}

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

Alias for #each.

#external_encodingEncoding?

Returns an Encoding object that represents the encoding of the string; see Encodings:

strio = StringIO.new('foo')
strio.external_encoding # => #<Encoding:UTF-8>

Returns nil if self has no string and is in write mode:

strio = StringIO.new(nil, 'w+')
strio.external_encoding # => nil
[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1903

static VALUE
strio_external_encoding(VALUE self)
{
    struct StringIO *ptr = StringIO(self);
    return rb_enc_from_encoding(get_enc(ptr));
}

#fcntl

[ GitHub ]

#fileno

[ GitHub ]

#flush

[ GitHub ]

#fsync

[ GitHub ]

#getbyteInteger?

Reads and returns the next integer byte (not character) from the stream:

s = 'foo'
s.bytes       # => [102, 111, 111]
strio = StringIO.new(s)
strio.getbyte # => 102
strio.getbyte # => 111
strio.getbyte # => 111

Returns nil if at end-of-stream:

strio.eof?    # => true
strio.getbyte # => nil

Returns a byte, not a character:

s = 'Привет'
s.bytes
# => [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
strio = StringIO.new(s)
strio.getbyte # => 208
strio.getbyte # => 159

s = 'こんにちは'
s.bytes
# => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
strio = StringIO.new(s)
strio.getbyte # => 227
strio.getbyte # => 129

Related: #each_byte, #ungetbyte, #getc.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 998

static VALUE
strio_getbyte(VALUE self)
{
    struct StringIO *ptr = readable(self);
    int c;
    if (eos_p(ptr)) {
	return Qnil;
    }
    c = RSTRING_PTR(ptr->string)[ptr->pos++];
    return CHR2FIX(c);
}

#getccharacter, ...

Reads and returns the next character (or byte; see below) from the stream:

strio = StringIO.new('foo')
strio.getc # => "f"
strio.getc # => "o"
strio.getc # => "o"

Returns nil if at end-of-stream:

strio.eof? # => true
strio.getc # => nil

Returns characters, not bytes:

strio = StringIO.new('Привет')
strio.getc # => "П"
strio.getc # => "р"

strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.getc # => "ん"

In each of the examples above, the stream is positioned at the beginning of a character; in other cases that need not be true:

strio = StringIO.new('こんにちは')  # Five 3-byte characters.
strio.pos = 3 # => 3     # At beginning of second character; returns character.
strio.getc    # => "ん"
strio.pos = 4 # => 4     # At second byte of second character; returns byte.
strio.getc    # => "\x82"
strio.pos = 5 # => 5     # At third byte of second character; returns byte.
strio.getc    # => "\x93"

Related: #getbyte, #putc, #ungetc.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 972

static VALUE
strio_getc(VALUE self)
{
    struct StringIO *ptr = readable(self);
    rb_encoding *enc = get_enc(ptr);
    VALUE str = ptr->string;
    long pos = ptr->pos;
    int len;
    char *p;

    if (eos_p(ptr)) {
	return Qnil;
    }
    p = RSTRING_PTR(str)+pos;
    len = rb_enc_mbclen(p, RSTRING_END(str), enc);
    ptr->pos += len;
    return enc_subseq(str, pos, len, enc);
}

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

Reads and returns a line from the stream; returns nil if at end-of-stream.

Side effects:

  • Increments stream position by the number of bytes read.

  • Assigns the return value to global variable $_.

With no arguments given, reads a line using the default record separator (global variable $/,* whose initial value is "\n"):

strio = StringIO.new(TEXT)
strio.pos  # => 0
strio.gets # => "First line\n"
strio.pos  # => 11
$_         # => "First line\n"
strio.gets # => "Second line\n"
strio.read # => "\nFourth line\nFifth line\n"
strio.eof? # => true
strio.gets # => nil

strio = StringIO.new('Привет')  # Six 2-byte characters
strio.pos  # => 0
strio.gets # => "Привет"
strio.pos  # => 12

Argument sep

With only string argument sep given, reads a line using that string as the record separator:

strio = StringIO.new(TEXT)
strio.gets(' ') # => "First "
strio.gets(' ') # => "line\nSecond "
strio.gets(' ') # => "line\n\nFourth "

Argument limit

With only integer argument limit given, reads a line using the default record separator; limits the size (in characters) of each line to the given limit:

strio = StringIO.new(TEXT)
strio.gets(10) # => "First line"
strio.gets(10) # => "\n"
strio.gets(10) # => "Second lin"
strio.gets(10) # => "e\n"

Arguments sep and limit

With arguments sep and limit both given, honors both:

strio = StringIO.new(TEXT)
strio.gets(' ', 10) # => "First "
strio.gets(' ', 10) # => "line\nSecon"
strio.gets(' ', 10) # => "d "

Position

As stated above, method gets reads and returns the next line in the stream.

In the examples above each strio object starts with its position at beginning-of-stream; but in other cases the position may be anywhere:

strio = StringIO.new(TEXT)
strio.pos = 12
strio.gets # => "econd line\n"

The position need not be at a character boundary:

strio = StringIO.new('Привет') # Six 2-byte characters.
strio.pos = 2                  # At beginning of second character.
strio.gets # => "ривет"
strio.pos = 3                  # In middle of second character.
strio.gets # => "\x80ивет"

Special Record Separators

Like some methods in class ::IO, method gets honors two special record separators; see Special Line Separators:

strio = StringIO.new(TEXT)
strio.gets('')  # Read "paragraph" (up to empty line).
# => "First line\nSecond line\n\n"

strio = StringIO.new(TEXT)
strio.gets(nil) # "Slurp": read all.
# => "First line\nSecond line\n\nFourth line\nFifth line\n"

Keyword Argument chomp

With keyword argument chomp given as true (the default is false), removes the trailing newline (if any) from the returned line:

strio = StringIO.new(TEXT)
strio.gets              # => "First line\n"
strio.gets(chomp: true) # => "Second line"

Related: #each_line, #readlines, Kernel#puts.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1434

static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
{
    struct StringIO *ptr = readable(self);
    struct getline_arg arg;
    VALUE str;

    if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
	if (NIL_P(ptr->string)) return Qnil;
	return rb_enc_str_new(0, 0, get_enc(ptr));
    }

    str = strio_getline(&arg, ptr);
    rb_lastline_set(str);
    return str;
}

#initialize_copy(orig)

This method is for internal use only.
[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 723

static VALUE
strio_copy(VALUE copy, VALUE orig)
{
    struct StringIO *ptr, *old_ptr;
    VALUE old_string = Qundef;

    orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
    if (copy == orig) return copy;
    ptr = StringIO(orig);
    old_ptr = check_strio(copy);
    if (old_ptr) {
	old_string = old_ptr->string;
	strio_free(old_ptr);
    }
    DATA_PTR(copy) = ptr;
    RB_OBJ_WRITTEN(copy, old_string, ptr->string);
    RBASIC(copy)->flags &= ~STRIO_READWRITE;
    RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE;
    ++ptr->count;
    return copy;
}

#internal_encodingnil

Returns nil; for compatibility with ::IO.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1917

static VALUE
strio_internal_encoding(VALUE self)
{
    return Qnil;
}

#isatty

[ GitHub ]

#lengthInteger Also known as: #size

Returns the number of bytes in the string in self:

StringIO.new('hello').size     # => 5  # Five 1-byte characters.
StringIO.new('тест').size      # => 8  # Four 2-byte characters.
StringIO.new('こんにちは').size # => 15 # Five 3-byte characters.
[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1851

static VALUE
strio_size(VALUE self)
{
    VALUE string = StringIO(self)->string;
    if (NIL_P(string)) {
	return INT2FIX(0);
    }
    return ULONG2NUM(RSTRING_LEN(string));
}

#pid

[ GitHub ]

#pread(maxlen, offset) ⇒ String #pread(maxlen, offset, out_string) ⇒ String

See IO#pread.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1731

static VALUE
strio_pread(int argc, VALUE *argv, VALUE self)
{
    VALUE rb_len, rb_offset, rb_buf;
    rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
    long len = NUM2LONG(rb_len);
    long offset = NUM2LONG(rb_offset);

    if (len < 0) {
	rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
    }

    if (len == 0) {
	if (NIL_P(rb_buf)) {
	    return rb_str_new("", 0);
	}
	return rb_buf;
    }

    if (offset < 0) {
	rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
    }

    struct StringIO *ptr = readable(self);

    if (outside_p(ptr, offset)) {
	rb_eof_error();
    }

    if (NIL_P(rb_buf)) {
	return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
    }

    long rest = RSTRING_LEN(ptr->string) - offset;
    if (len > rest) len = rest;
    rb_str_resize(rb_buf, len);
    rb_enc_associate(rb_buf, rb_ascii8bit_encoding());
    MEMCPY(RSTRING_PTR(rb_buf), RSTRING_PTR(ptr->string) + offset, char, len);
    return rb_buf;
}

#putc(obj) ⇒ Object

See IO#putc.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1622

static VALUE
strio_putc(VALUE self, VALUE ch)
{
    struct StringIO *ptr = writable(self);
    VALUE str;

    check_modifiable(ptr);
    if (RB_TYPE_P(ch, T_STRING)) {
	if (NIL_P(ptr->string)) return ch;
	str = rb_str_substr(ch, 0, 1);
    }
    else {
	char c = NUM2CHR(ch);
	if (NIL_P(ptr->string)) return ch;
	str = rb_str_new(&c, 1);
    }
    strio_write(self, str);
    return ch;
}

#read([length [, outbuf]]) ⇒ String, ...

See IO#read.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1656

static VALUE
strio_read(int argc, VALUE *argv, VALUE self)
{
    struct StringIO *ptr = readable(self);
    VALUE str = Qnil;
    long len;
    int binary = 0;

    switch (argc) {
      case 2:
	str = argv[1];
	if (!NIL_P(str)) {
	    StringValue(str);
	    rb_str_modify(str);
	}
	/* fall through */
      case 1:
	if (!NIL_P(argv[0])) {
	    len = NUM2LONG(argv[0]);
	    if (len < 0) {
		rb_raise(rb_eArgError, "negative length %ld given", len);
	    }
	    if (eos_p(ptr)) {
		if (!NIL_P(str)) rb_str_resize(str, 0);
		return len > 0 ? Qnil : rb_str_new(0, 0);
	    }
	    binary = 1;
	    break;
	}
	/* fall through */
      case 0:
	if (NIL_P(ptr->string)) return Qnil;
	len = RSTRING_LEN(ptr->string);
	if (len <= ptr->pos) {
	    rb_encoding *enc = get_enc(ptr);
	    if (NIL_P(str)) {
		str = rb_str_new(0, 0);
	    }
	    else {
		rb_str_resize(str, 0);
	    }
	    rb_enc_associate(str, enc);
	    return str;
	}
	else {
	    len -= ptr->pos;
	}
	break;
      default:
	rb_error_arity(argc, 0, 2);
    }
    if (NIL_P(str)) {
	rb_encoding *enc = binary ? rb_ascii8bit_encoding() : get_enc(ptr);
	str = strio_substr(ptr, ptr->pos, len, enc);
    }
    else {
	long rest = RSTRING_LEN(ptr->string) - ptr->pos;
	if (len > rest) len = rest;
	rb_str_resize(str, len);
	MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
	if (!binary) {
	    rb_enc_copy(str, ptr->string);
	}
    }
    ptr->pos += RSTRING_LEN(str);
    return str;
}

#readlines(sep = $/, chomp: false) ⇒ Array #readlines(limit, chomp: false) ⇒ Array #readlines(sep, limit, chomp: false) ⇒ Array

See IO#readlines.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1506

static VALUE
strio_readlines(int argc, VALUE *argv, VALUE self)
{
    VALUE ary, line;
    struct StringIO *ptr = readable(self);
    struct getline_arg arg;

    if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
	rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
    }

    ary = rb_ary_new();
    while (!NIL_P(line = strio_getline(&arg, ptr))) {
	rb_ary_push(ary, line);
    }
    return ary;
}

#reopen(other, mode = 'r+') ⇒ self

Reinitializes the stream with the given other (string or StringIO) and mode; see IO.new:

StringIO.open('foo') do |strio|
  p strio.string
  strio.reopen('bar')
  p strio.string
  other_strio = StringIO.new('baz')
  strio.reopen(other_strio)
  p strio.string
  other_strio.close
end

Output:

"foo"
"bar"
"baz"
[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 823

static VALUE
strio_reopen(int argc, VALUE *argv, VALUE self)
{
    rb_io_taint_check(self);
    if (argc == 1 && !RB_TYPE_P(*argv, T_STRING)) {
	return strio_copy(self, *argv);
    }
    return strio_init(argc, argv, StringIO(self), self);
}

#rewind0

Sets the current position and line number to zero; see Position and Line Number.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 873

static VALUE
strio_rewind(VALUE self)
{
    struct StringIO *ptr = StringIO(self);
    ptr->pos = 0;
    ptr->lineno = 0;
    return INT2FIX(0);
}

#seek(offset, whence = SEEK_SET) ⇒ 0

Sets the position to the given integer offset (in bytes), with respect to a given constant whence; see IO#seek.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 890

static VALUE
strio_seek(int argc, VALUE *argv, VALUE self)
{
    VALUE whence;
    struct StringIO *ptr = StringIO(self);
    long amount, offset;

    rb_scan_args(argc, argv, "11", NULL, &whence);
    amount = NUM2LONG(argv[0]);
    if (CLOSED(self)) {
	rb_raise(rb_eIOError, "closed stream");
    }
    switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
      case 0:
	offset = 0;
	break;
      case 1:
	offset = ptr->pos;
	break;
      case 2:
	if (NIL_P(ptr->string)) {
	    offset = 0;
	} else {
	    offset = RSTRING_LEN(ptr->string);
	}
	break;
      default:
	error_inval("invalid whence");
    }
    if (amount > LONG_MAX - offset || amount + offset < 0) {
	error_inval(0);
    }
    ptr->pos = amount + offset;
    return INT2FIX(0);
}

#set_encoding(ext_enc, [int_enc[, opt]]) ⇒ strio

Specify the encoding of the StringIO as ext_enc. Use the default external encoding if ext_enc is nil. 2nd argument int_enc and optional hash opt argument are ignored; they are for API compatibility to ::IO.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1933

static VALUE
strio_set_encoding(int argc, VALUE *argv, VALUE self)
{
    rb_encoding* enc;
    struct StringIO *ptr = StringIO(self);
    VALUE ext_enc, int_enc, opt;

    argc = rb_scan_args(argc, argv, "11:", &ext_enc, &int_enc, &opt);

    if (NIL_P(ext_enc)) {
	enc = rb_default_external_encoding();
    }
    else {
	enc = rb_find_encoding(ext_enc);
	if (!enc) {
	    rb_io_enc_t convconfig;
	    int oflags;
	    rb_io_mode_t fmode;
	    VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
	    rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
	    enc = convconfig.enc2;
	}
    }
    ptr->enc = enc;
    if (!NIL_P(ptr->string) && WRITABLE(self) && !str_chilled_p(ptr->string)) {
	rb_enc_associate(ptr->string, enc);
    }

    return self;
}

#set_encoding_by_bomstrio?

Sets the encoding according to the BOM (Byte Order Mark) in the string.

Returns self if the BOM is found, otherwise +nil.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1973

static VALUE
strio_set_encoding_by_bom(VALUE self)
{
    struct StringIO *ptr = StringIO(self);

    if (!set_encoding_by_bom(ptr)) return Qnil;
    return rb_enc_from_encoding(ptr->enc);
}

#lengthInteger #sizeInteger

Alias for #length.

#synctrue

Returns true; implemented only for compatibility with other stream classes.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 932

static VALUE
strio_get_sync(VALUE self)
{
    StringIO(self);
    return Qtrue;
}

#sync=

[ GitHub ]

#tell

[ GitHub ]

#truncate(integer) ⇒ 0

Truncates the buffer string to at most integer bytes. The stream must be opened for writing.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1868

static VALUE
strio_truncate(VALUE self, VALUE len)
{
    VALUE string = writable(self)->string;
    long l = NUM2LONG(len);
    long plen;
    if (l < 0) {
	error_inval("negative length");
    }
    if (NIL_P(string)) return 0;
    plen = RSTRING_LEN(string);
    rb_str_resize(string, l);
    if (plen < l) {
	MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
    }
    return INT2FIX(0);
}

#ungetbyte(byte) ⇒ nil

Pushes back (“unshifts”) an 8-bit byte onto the stream; see Byte IO.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1088

static VALUE
strio_ungetbyte(VALUE self, VALUE c)
{
    struct StringIO *ptr = readable(self);

    check_modifiable(ptr);
    if (NIL_P(ptr->string)) return Qnil;
    if (NIL_P(c)) return Qnil;
    if (RB_INTEGER_TYPE_P(c)) {
	/* rb_int_and() not visible from exts */
	VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
	const char cc = NUM2INT(v) & 0xFF;
	strio_unget_bytes(ptr, &cc, 1);
    }
    else {
	StringValue(c);
	strio_unget_string(ptr, c);
    }
    return Qnil;
}

#ungetc(character) ⇒ nil

Pushes back (“unshifts”) a character or integer onto the stream; see Character IO.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1046

static VALUE
strio_ungetc(VALUE self, VALUE c)
{
    struct StringIO *ptr = readable(self);
    rb_encoding *enc, *enc2;

    check_modifiable(ptr);
    if (NIL_P(ptr->string)) return Qnil;
    if (NIL_P(c)) return Qnil;
    if (RB_INTEGER_TYPE_P(c)) {
	int len, cc = NUM2INT(c);
	char buf[16];

	enc = rb_enc_get(ptr->string);
	len = rb_enc_codelen(cc, enc);
	if (len <= 0) {
	    rb_enc_uint_chr(cc, enc); /* to raise an exception */
	    UNREACHABLE;
	}
	rb_enc_mbcput(cc, buf, enc);
	return strio_unget_bytes(ptr, buf, len);
    }
    else {
	StringValue(c);
	if (RSTRING_LEN(c) == 0) return Qnil;
	enc = rb_enc_get(ptr->string);
	enc2 = rb_enc_get(c);
	if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
	    c = rb_str_conv_enc(c, enc2, enc);
	}
	strio_unget_string(ptr, c);
	return Qnil;
    }
}

#write(string, ...) ⇒ Integer #syswrite(string) ⇒ Integer

Appends the given string to the underlying buffer string. The stream must be opened for writing. If the argument is not a string, it will be converted to a string using to_s. Returns the number of bytes written. See IO#write.

[ GitHub ]

  
# File 'ext/stringio/stringio.c', line 1534

static VALUE
strio_write_m(int argc, VALUE *argv, VALUE self)
{
    long len = 0;
    while (argc-- > 0) {
	/* StringIO can't exceed long limit */
	len += strio_write(self, *argv++);
    }
    return LONG2NUM(len);
}