class StringIO - Documentation for Ruby 4.0 (original) (raw)

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

You can create a StringIO instance using:

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

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:

Initial state:

strio = StringIO.new('foobarbaz', 'r') strio.pos
strio.string

May be read anywhere:

strio.gets(3) strio.gets(3) strio.pos = 9 strio.gets(3)

May not be written:

strio.write('foo')

'w': Write-Only

Mode specified as one of:

Initial state:

strio = StringIO.new('foo', 'w') strio.pos
strio.string

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

strio.write('foobar') strio.string strio.rewind strio.write('FOO') strio.string strio.pos = 3 strio.write('BAR') strio.string strio.pos = 9 strio.write('baz') strio.string

May not be read:

strio.read

'a': Append-Only

Mode specified as one of:

Initial state:

strio = StringIO.new('foo', 'a') strio.pos
strio.string

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

strio.write('bar') strio.string strio.write('baz') strio.string strio.pos = 400 strio.write('bat') strio.string

May not be read:

strio.gets

'r+': Read/Write

Mode specified as one of:

Initial state:

strio = StringIO.new('foobar', 'r+') strio.pos
strio.string

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

strio.write('FOO') strio.string strio.write('BAR') strio.string strio.write('BAZ') strio.string strio.pos = 12 strio.write('BAT') strio.string

May be read anywhere:

strio.pos = 0 strio.gets(3) strio.pos = 6 strio.gets(3) strio.pos = 400 strio.gets(3)

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

Mode specified as one of:

Initial state:

strio = StringIO.new('foo', 'w+') strio.pos
strio.string

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

strio.write('foobar') strio.string strio.rewind strio.write('FOO') strio.string strio.write('BAR') strio.string strio.write('BAZ') strio.string strio.pos = 12 strio.write('BAT') strio.string

May be read anywhere:

strio.rewind strio.gets(3) strio.gets(3) strio.pos = 12 strio.gets(3) strio.pos = 400 strio.gets(3)

'a+': Read/Append

Mode specified as one of:

Initial state:

strio = StringIO.new('foo', 'a+') strio.pos
strio.string

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

strio.write('bar') strio.string strio.write('baz') strio.string strio.pos = 400 strio.write('bat') strio.string

May be read anywhere:

strio.rewind strio.gets(3) strio.gets(3) strio.pos = 9 strio.gets(3) strio.pos = 400 strio.gets(3)

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:

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

Examples:

strio = StringIO.new('foo', 'rt') strio.external_encoding data = "\u9990\u9991\u9992\u9993\u9994" strio = StringIO.new(data, 'rb') strio.external_encoding

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

StringIO.new(data, '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:

These instance methods are relevant:

Examples:

strio = StringIO.new('foo', 'rt')
strio.external_encoding data = "\u9990\u9991\u9992\u9993\u9994" strio = StringIO.new(data, 'rb') strio.external_encoding strio = StringIO.new('foo') strio.external_encoding strio.set_encoding('US-ASCII') strio.external_encoding

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:

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

Examples:

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

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 strio.pos
strio.getc
strio.pos
strio.gets
strio.pos
strio.pos = 24 strio.gets
strio.pos

strio = StringIO.new('тест') strio.pos = 0 strio.read
strio.pos = 1 strio.read
strio.pos = 2 strio.read

strio = StringIO.new(TEXT) strio.pos = 15 a = [] strio.each_line {|line| a.push(line) } a
strio.pos

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:

Examples:

strio = StringIO.new('foo') strio.pos
strio.putc('b') strio.string strio.pos
strio.write('r') strio.string strio.pos
strio.puts('ew') strio.string strio.pos
strio.pos = 8 strio.write('foo') strio.string strio.pos

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
strio.string strio.ungetc('x') strio.pos
strio.string

This method does not affect the position:

Examples:

strio = StringIO.new('foobar') strio.pos
strio.truncate(3) strio.string strio.pos
strio.pos = 500 strio.truncate(0) strio.string strio.pos

Line Number

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

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 strio.lineno strio.gets
strio.lineno strio.getc
strio.lineno strio.gets
strio.lineno strio.gets
strio.lineno strio.gets
strio.lineno

Setting the position does not affect the line number:

strio.pos = 0 strio.lineno strio.gets
strio.pos
strio.lineno

And setting the line number does not affect the position:

strio.lineno = 10 strio.pos
strio.gets
strio.lineno strio.pos

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:

Other relevant methods:

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):

utf8_bom = "\xEF\xBB\xBF" string = utf8_bom + 'foo' string.bytes
strio.string.bytes.take(3) strio = StringIO.new(string, 'rb') strio.string.bytes
strio.external_encoding
strio.gets

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

strio.set_encoding_by_bom strio.string.bytes
strio.external_encoding strio.rewind
strio.gets

Basic Stream IO

Basic Reading

You can read from the stream using these instance methods:

You can iterate over the stream using these instance methods:

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

Basic Writing

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

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:

Line IO

Reading:

Writing:

Character IO

Reading:

Writing:

Byte IO

Reading:

Writing:

Codepoint IO

Reading:

Constants

MAX_LENGTH

Maximum length that a StringIO instance can hold

VERSION

The version string

Public Class Methods

Source

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);

}

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?
strio.closed_write? strio.close

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

strio = StringIO.new('foo'.freeze) strio.string
strio.closed_read?
strio.closed_write? 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: StringIO.open (passes the StringIO object to the block; closes the object automatically on block exit).

Source

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); }

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

With no block given, returns the new instance:

strio = StringIO.open

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 }

Related: StringIO.new.

Public Instance Methods

Source

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;

}

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

Source

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

Closes self for both reading and writing; returns nil:

strio = StringIO.new strio.closed? strio.close
strio.closed? strio.read
strio.write

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

Source

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; }

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

strio = StringIO.new strio.closed_read?
strio.close_read
strio.closed_read?
strio.closed_write? strio.read

Related: StringIO#close, StringIO#close_write.

Source

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; }

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

strio = StringIO.new strio.closed_write? strio.close_write
strio.closed_write? strio.closed_read?
strio.write('foo')

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

Source

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

Returns whether self is closed for both reading and writing:

strio = StringIO.new strio.closed?
strio.close_read strio.closed?
strio.close_write strio.closed?

Related: StringIO.closed_read?, StringIO.closed_write?.

Source

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

Returns whether self is closed for reading:

strio = StringIO.new strio.closed_read?
strio.close_read strio.closed_read?

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

Source

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

Returns whether self is closed for writing:

strio = StringIO.new strio.closed_write? strio.close_write strio.closed_write?

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

Source

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;

}

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')
strio.each_byte {|byte| bytes.push(byte) } strio.eof? bytes bytes = [] strio = StringIO.new('тест')
strio.each_byte {|byte| bytes.push(byte) } bytes bytes = [] strio = StringIO.new('こんにちは')
strio.each_byte {|byte| bytes.push(byte) } bytes

The position in the stream matters:

bytes = [] strio = StringIO.new('こんにちは') strio.getc strio.pos
strio.each_byte {|byte| bytes.push(byte) } bytes

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

strio.eof? strio.each_byte {|byte| fail 'Boo!' } strio.eof?

With no block given, returns a new Enumerator.

Related: StringIO#each_char, StringIO#each_codepoint, StringIO#each_line.

Source

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;

}

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? chars
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
strio.each_char {|char| chars.push(char) } chars

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

strio.eof? strio.each_char {|char| fail 'Boo!' } strio.eof?

With no block given, returns a new Enumerator.

Related: StringIO#each_byte, StringIO#each_codepoint, StringIO#each_line.

Source

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;

}

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? codepoints codepoints = [] strio = StringIO.new('тест') strio.each_codepoint {|codepoint| codepoints.push(codepoint) } codepoints codepoints = [] strio = StringIO.new('こんにちは') strio.each_codepoint {|codepoint| codepoints.push(codepoint) } codepoints

Position in the stream matters:

codepoints = [] strio = StringIO.new('こんにちは') strio.getc strio.pos
strio.each_codepoint {|codepoint| codepoints.push(codepoint) } codepoints

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

strio.eof? strio.each_codepoint {|codepoint| fail 'Boo!' } strio.eof?

With no block given, returns a new Enumerator.

Related: StringIO#each_byte, StringIO#each_char, StringIO#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?

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 StringIO#pos):

strio = StringIO.new(TEXT) strio.pos = 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 = 'こんにちは'
strio = StringIO.new(s) strio.pos = 3
strio.each_line {|line| p line } strio.pos = 4
strio.each_line {|line| p line } strio.pos = 5
strio.each_line {|line| p line }

Output:

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

Special Record Separators

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

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

Output:

"First line\nSecond line\n\n" "Fourth line\nFifth line\n"

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

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: StringIO.each_byte, StringIO.each_char, StringIO.each_codepoint.

Source

Also aliased as: eof?

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

strio = StringIO.new('foo') strio.pos
strio.eof? strio.read strio.pos
strio.eof? strio.close_read strio.eof?

Related: StringIO#pos.

Alias for: eof

Source

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

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

strio = StringIO.new('foo') strio.external_encoding

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

strio = StringIO.new(nil, 'w+') strio.external_encoding

Source

static VALUE strio_unimpl(int argc, VALUE *argv, VALUE self) { StringIO(self); rb_notimplement();

UNREACHABLE;

}

Raises NotImplementedError.

Source

static VALUE strio_nil(VALUE self) { StringIO(self); return Qnil; }

Returns nil; for compatibility with IO.

Source

static VALUE strio_self(VALUE self) { StringIO(self); return self; }

Returns self; for compatibility with IO.

Source

static VALUE strio_0(VALUE self) { StringIO(self); return INT2FIX(0); }

Returns 0; for compatibility with IO.

Source

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); }

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

s = 'foo' s.bytes
strio = StringIO.new(s) strio.getbyte strio.getbyte strio.getbyte

Returns nil if at end-of-stream:

strio.eof?
strio.getbyte

Returns a byte, not a character:

s = 'Привет' s.bytes

strio = StringIO.new(s) strio.getbyte strio.getbyte

s = 'こんにちは' s.bytes

strio = StringIO.new(s) strio.getbyte strio.getbyte

Related: each_byte, ungetbyte, getc.

Source

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);

}

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

strio = StringIO.new('foo') strio.getc strio.getc strio.getc

Returns nil if at end-of-stream:

strio.eof? strio.getc

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('こんにちは')
strio.pos = 3 strio.getc
strio.pos = 4 strio.getc
strio.pos = 5 strio.getc

Related: getbyte, putc, ungetc.

Source

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;

}

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

Side effects:

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
strio.gets strio.pos
$_
strio.gets strio.read strio.eof? strio.gets

strio = StringIO.new('Привет')
strio.pos
strio.gets strio.pos

Argument sep

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

strio = StringIO.new(TEXT) strio.gets(' ') strio.gets(' ') strio.gets(' ')

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) strio.gets(10) strio.gets(10) strio.gets(10)

Arguments sep and limit

With arguments sep and limit both given, honors both:

strio = StringIO.new(TEXT) strio.gets(' ', 10) strio.gets(' ', 10) strio.gets(' ', 10)

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

The position need not be at a character boundary:

strio = StringIO.new('Привет') strio.pos = 2
strio.gets strio.pos = 3
strio.gets

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('')

strio = StringIO.new(TEXT) strio.gets(nil)

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
strio.gets(chomp: true)

Related: each_line, readlines, Kernel#puts.

Source

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

Returns nil; for compatibility with IO.

Source

static VALUE strio_false(VALUE self) { StringIO(self); return Qfalse; }

Returns false; for compatibility with IO.

Also aliased as: tty?

Source

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

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

Source

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

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

Source

static VALUE strio_nil(VALUE self) { StringIO(self); return Qnil; }

Returns nil; for compatibility with IO.

Source

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

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

Source

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; }

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

Source

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;

}

See IO#pread.

Source

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;

}

See IO#putc.

Source

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;

}

See IO#read.

Source

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;

}

See IO#readlines.

Source

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); }

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"

Source

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

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

Source

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);

}

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

Source

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;

}

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.

Source

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);

}

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

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

Source

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

Returns the number of bytes in the string in self:

StringIO.new('hello').size
StringIO.new('тест').size
StringIO.new('こんにちは').size

Source

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

Returns underlying string:

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

Output:

"foo" "bar"

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

Source

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;

}

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: StringIO#string (returns the stored string).

Source

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

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

Source

static VALUE strio_first(VALUE self, VALUE arg) { StringIO(self); return arg; }

Returns the argument unchanged. Just for compatibility to IO.

Source

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

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

Source

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); }

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

Returns false; for compatibility with IO.

Source

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;

}

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

Source

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;
}

}

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

Source

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); }

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.