Spec-Zone.ru › Ruby 4.0

class StringIO

Родительский класс:
Object
Подключённые модули:
Enumerable, IO::generic_readable, IO::generic_writable

Класс StringIO поддерживает доступ к строке как к потоку, в некотором отношении подобному классу IO.

Создать экземпляр StringIO можно с помощью:

  • StringIO.new: возвращает новый объект StringIO, содержащий заданную строку.

  • StringIO.open: передаёт новый объект StringIO заданному блоку.

Как и поток IO, поток StringIO имеет определённые свойства:

  • Режим чтения/записи: можно ли читать из потока, записывать в него, добавлять данные и т. д.; см. раздел Режим чтения/записи.

  • Режим данных: только текст или двоичные данные; см. раздел Режим данных.

  • Кодировки: внутренняя и внешняя кодировки; см. раздел Кодировки.

  • Позиция: место в потоке, откуда будет выполнено следующее чтение или куда будет выполнена следующая запись; см. раздел Позиция.

  • Номер строки: специальная «позиция», ориентированная на строки (отличается от упомянутой выше позиции); см. раздел Номер строки.

  • Открыт/закрыт: открыт или закрыт поток для чтения или записи. См. раздел Открытые/закрытые потоки.

  • BOM: метка порядка байтов; см. раздел Метка порядка байтов.

Об этих примерах

В примерах на этой странице предполагается, что подключён StringIO:

require 'stringio'

И что определена эта константа:

TEXT = <<EOT
First line
Second line

Fourth line
Fifth line
EOT

Свойства потока

Режим чтения/записи

Краткое описание

Режим Изначально очищен? Чтение Запись
'r': только для чтения Нет В любом месте Ошибка
'w': только для записи Да Ошибка В любом месте
'a': только добавление Нет Ошибка Только в конце
'r+': чтение/запись Нет В любом месте В любом месте
'w+': чтение-запись Да В любом месте В любом месте
'a+': чтение/добавление Нет В любом месте Только в конце

В каждом разделе ниже описан режим чтения/записи.

Любой режим можно указать строкой или файловой константой; пример:

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

'r': только для чтения

Режим задаётся одним из следующих способов:

  • Строка: 'r'.

  • Константа: File::RDONLY.

Начальное состояние:

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

Читать можно в любом месте:

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

Запись невозможна:

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

'w': только для записи

Режим задаётся одним из следующих способов:

  • Строка: 'w'.

  • Константа: File::WRONLY.

Начальное состояние:

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

Записывать можно в любом месте (даже за концом потока):

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.

Чтение невозможно:

strio.read  # Raises IOError: not opened for reading

'a': только добавление

Режим задаётся одним из следующих способов:

  • Строка: 'a'.

  • Константа: File::WRONLY | File::APPEND.

Начальное состояние:

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

Записывать можно только в конце; позиция не влияет на запись:

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

Чтение невозможно:

strio.gets  # Raises IOError: not opened for reading

'r+': чтение/запись

Режим задаётся одним из следующих способов:

  • Строка: 'r+'.

  • Константа: File::RDRW.

Начальное состояние:

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

Записывать можно в любом месте (даже за концом потока):

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.

Читать можно в любом месте:

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

'w+': чтение/запись (изначально очищен)

Режим задаётся одним из следующих способов:

  • Строка: 'w+'.

  • Константа: File::RDWR | File::TRUNC.

Начальное состояние:

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

Записывать можно в любом месте (даже за концом потока):

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.

Читать можно в любом месте:

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+': чтение/добавление

Режим задаётся одним из следующих способов:

  • Строка: 'a+'.

  • Константа: File::RDWR | File::APPEND.

Начальное состояние:

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

Записывать можно только в конце; rewind; позиция не влияет на запись:

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

Читать можно в любом месте:

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 режим

Чтобы указать, следует ли обрабатывать поток как текст или как двоичные данные, к любому из описанных выше строковых режимов чтения/записи можно добавить один из следующих суффиксов:

  • 't': текст; инициализирует кодировку как Encoding::UTF_8.

  • 'b': двоичные данные; инициализирует кодировку как Encoding::ASCII_8BIT.

Если не указан ни один из них, по умолчанию поток содержит текстовые данные.

Примеры:

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

Если режим данных указан, режим чтения/записи нельзя опускать:

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

Текстовый поток можно преобразовать в двоичный, вызвав метод экземпляра binmode; двоичный поток нельзя преобразовать в текстовый.

Кодировки

У потока есть кодировка; см. раздел Кодировки.

Начальная кодировка нового или повторно открытого потока зависит от его режима данных:

  • Текст: Encoding::UTF_8.

  • Двоичные данные: Encoding::ASCII_8BIT.

Важны следующие методы экземпляра:

  • external_encoding: возвращает текущую кодировку потока в виде объекта Encoding.

  • internal_encoding: возвращает nil; у потока нет внутренней кодировки.

  • set_encoding: задаёт кодировку потока.

  • set_encoding_by_bom: задаёт кодировку потока в соответствии с BOM (меткой порядка байтов) потока.

Примеры:

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>

Позиция

У потока есть позиция — целочисленное смещение (в байтах) внутри потока. Начальная позиция потока равна нулю.

Получение и установка позиции

Каждый из этих методов устанавливает позицию нового или повторно открытого потока в ноль:

  • ::new: возвращает новый поток.

  • ::open: передаёт новый поток блоку.

  • reopen: повторно инициализирует поток.

Каждый из этих методов запрашивает, получает или устанавливает позицию, не изменяя при этом поток иным образом:

  • eof?: возвращает, находится ли позиция в конце потока.

  • pos: возвращает позицию.

  • pos=: задаёт позицию.

  • rewind: устанавливает позицию в ноль.

  • seek: задаёт позицию.

Примеры:

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

Позиция до и после чтения

За исключением pread, метод чтения из потока (см. раздел Основы чтения) начинает чтение с текущей позиции.

За исключением pread, метод чтения перемещает позицию за пределы прочитанной подстроки.

Примеры:

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.

Позиция до и после записи

Каждый из этих методов начинает запись с текущей позиции и перемещает позицию в конец записанной подстроки:

  • putc: записывает заданный символ.

  • write: записывает заданные объекты как строки.

  • Kernel#puts: записывает заданные объекты как строки, добавляя после каждой перевод строки.

Примеры:

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

Каждый из этих методов записывает данные перед текущей позицией и уменьшает позицию, чтобы записанные данные стали следующими для чтения:

  • ungetbyte: помещает заданный байт обратно в поток.

  • ungetc: помещает заданный символ обратно в поток.

Примеры:

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"

Этот метод не влияет на позицию:

  • truncate: усекает строку потока до заданного размера.

Примеры:

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

Номер строки

У потока есть номер строки, изначально равный нулю:

  • Метод lineno возвращает номер строки.

  • Метод lineno= задаёт номер строки.

На номер строки может влиять чтение (но никогда — запись); как правило, номер строки увеличивается каждый раз при чтении разделителя записей (по умолчанию: "\n").

Примеры:

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

Установка позиции не влияет на номер строки:

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

И установка номера строки не влияет на позицию:

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

Открытые/закрытые потоки

Новый поток открыт для чтения или записи и может быть открыт для обеих операций; см. раздел Режим чтения/записи.

Каждый из этих методов устанавливает режим чтения/записи нового или повторно открытого потока:

  • ::new: возвращает новый поток.

  • ::open: передаёт новый поток блоку.

  • reopen: повторно инициализирует поток.

Другие важные методы:

  • close: закрывает поток для чтения и записи.

  • close_read: закрывает поток для чтения.

  • close_write: закрывает поток для записи.

  • closed?: возвращает, закрыт ли поток для чтения и записи.

  • closed_read?: возвращает, закрыт ли поток для чтения.

  • closed_write?: возвращает, закрыт ли поток для записи.

BOM (метка порядка байтов)

Строка, переданная в ::new, ::open или reopen, может содержать в начале необязательную BOM (метку порядка байтов); BOM может повлиять на кодировку потока.

BOM (если она указана):

  • Хранится как часть строки потока.

  • Не влияет на кодировку немедленно.

  • Изначально считается частью потока.

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.

Можно вызвать метод экземпляра set_encoding_by_bom, чтобы «активировать» сохранённую BOM; после этого BOM:

  • По-прежнему хранится как часть строки потока.

  • Определяет (и может изменять) кодировку потока.

  • Больше не считается частью потока.

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.

Базовый ввод-вывод потока

Базовое чтение

Для чтения из потока можно использовать следующие методы экземпляра:

  • getbyte: читает и возвращает следующий байт.

  • getc: читает и возвращает следующий символ.

  • gets: читает и возвращает всю следующую строку или её часть.

  • read: читает и возвращает все оставшиеся данные потока или их часть.

  • readlines: читает оставшиеся данные потока и возвращает массив его строк.

  • Kernel#readline: работает как gets, но вызывает исключение при достижении конца потока.

Перебирать элементы потока можно с помощью следующих методов экземпляра:

  • each_byte: читает каждый оставшийся байт и передаёт его блоку.

  • each_char: читает каждый оставшийся символ и передаёт его блоку.

  • each_codepoint: читает каждую оставшуюся кодовую точку и передаёт её блоку.

  • each_line: читает каждую оставшуюся строку целиком или частично и передаёт прочитанную строку блоку

Этот метод экземпляра полезен в многопоточном приложении:

  • pread: читает и возвращает весь поток или его часть.

Базовая запись

Для записи в поток с перемещением позиции можно использовать следующие методы экземпляра:

  • putc: записывает заданный символ.

  • write: записывает заданные объекты в виде строк.

  • Kernel#puts записывает заданные объекты в виде строк, добавляя после каждой символ новой строки.

С помощью следующих методов экземпляра можно «поместить данные в начало» потока: каждый из них записывает данные перед текущей позицией и уменьшает позицию, чтобы записанные данные стали следующими для чтения.

  • ungetbyte: помещает заданный байт перед текущей позицией.

  • ungetc: помещает заданный символ перед текущей позицией.

Ещё один метод записи:

  • truncate: обрезает строку потока до заданного размера.

Ввод-вывод строк

Чтение:

  • gets: читает и возвращает следующую строку.

  • Kernel#readline: работает как gets, но вызывает исключение при достижении конца потока.

  • readlines: читает оставшиеся данные потока и возвращает массив его строк.

  • each_line: читает каждую оставшуюся строку и передаёт её блоку

Запись:

  • Kernel#puts: записывает заданные объекты, добавляя после каждого символ новой строки.

Ввод-вывод символов

Чтение:

  • each_char: читает каждый оставшийся символ и передаёт его блоку.

  • getc: читает и возвращает следующий символ.

Запись:

  • putc: записывает заданный символ.

  • ungetc.: помещает заданный символ перед текущей позицией.

Ввод-вывод байтов

Чтение:

  • each_byte: читает каждый оставшийся байт и передаёт его блоку.

  • getbyte: читает и возвращает следующий байт.

Запись:

  • ungetbyte: помещает заданный байт перед текущей позицией.

Ввод-вывод кодовых точек

Чтение:

  • each_codepoint: читает каждую оставшуюся кодовую точку и передаёт её блоку.

Константы

MAX_LENGTH

Максимальная длина, которую может иметь экземпляр StringIO

VERSION

Строка версии

Открытые методы класса

new(string = '', mode = 'r+') → new_stringio Показать исходный код
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);
}

Возвращает новый экземпляр StringIO, созданный на основе string и mode; экземпляр следует закрыть, когда он больше не нужен:

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

Если string заморожена, значением mode по умолчанию будет 'r':

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

Аргумент mode должен быть допустимым режимом доступа — строкой или целочисленной константой:

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

См. также: StringIO.open (передаёт объект StringIO блоку и автоматически закрывает объект по завершении блока).

open(string = '', mode = 'r+') → new_stringio Показать исходный код
open(string = '', mode = 'r+') {|strio| ... } → object
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);
}

Создаёт новый экземпляр StringIO, вызывая StringIO.new(string, mode).

Если блок не задан, возвращает новый экземпляр:

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

Если блок задан, вызывает его с новым экземпляром и возвращает значение блока; по завершении блока экземпляр закрывается:

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

См. также: StringIO.new.

Общедоступные методы экземпляра

binmode → self Показать исходный код
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;
}

Устанавливает двоичный режим данных в self; см. раздел Режим данных.

close → nil Показать исходный код
static VALUE
strio_close(VALUE self)
{
    StringIO(self);
    RBASIC(self)->flags &= ~STRIO_READWRITE;
    return Qnil;
}

Закрывает self для чтения и записи; возвращает 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

Связанные методы: StringIO#close_read, StringIO#close_write, StringIO.closed?.

close_read → nil Показать исходный код
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;
}

Закрывает self для чтения; настройка закрытия для записи остаётся без изменений; возвращает 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

Связанные методы: StringIO#close, StringIO#close_write.

close_write → nil Показать исходный код
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;
}

Закрывает self для записи; настройка закрытия для чтения остаётся без изменений; возвращает 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

Связанные методы: StringIO#close, StringIO#close_read, StringIO#closed_write?.

closed? → true or false Показать исходный код
static VALUE
strio_closed(VALUE self)
{
    StringIO(self);
    if (!CLOSED(self)) return Qfalse;
    return Qtrue;
}

Возвращает информацию о том, закрыт ли self для чтения и записи:

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.

Связанные методы: StringIO.closed_read?, StringIO.closed_write?.

closed_read? → true or false Показать исходный код
static VALUE
strio_closed_read(VALUE self)
{
    StringIO(self);
    if (READABLE(self)) return Qfalse;
    return Qtrue;
}

Возвращает информацию о том, закрыт ли self для чтения:

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

Связанные методы: StringIO#closed?, StringIO#closed_write?, StringIO#close_read.

closed_write? → true or false Показать исходный код
static VALUE
strio_closed_write(VALUE self)
{
    StringIO(self);
    if (WRITABLE(self)) return Qfalse;
    return Qtrue;
}

Возвращает информацию о том, закрыт ли self для записи:

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

Связанные методы: StringIO#close_write, StringIO#closed?, StringIO#closed_read?.

each Показать исходный код
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_line
each_byte {|byte| ... } → self Показать исходный код
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;
}

Если передан блок, вызывает его для каждого оставшегося байта в потоке; перемещает позицию потока в конец файла; возвращает 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]

Позиция в потоке имеет значение:

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]

Если достигнут конец файла, блок не вызывается:

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

Если блок не передан, возвращает новый Enumerator.

Связанные методы: StringIO#each_char, StringIO#each_codepoint, StringIO#each_line.

each_char {|char| ... } → self Показать исходный код
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;
}

Если передан блок, вызывает его для каждого оставшегося символа в потоке; перемещает позицию потока в конец файла; возвращает 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      # => ["こ", "ん", "に", "ち", "は"]

Позиция потока имеет значение:

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

Если достигнут конец потока, блок не вызывается:

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

Если блок не передан, возвращает новый Enumerator.

Связанные методы: StringIO#each_byte, StringIO#each_codepoint, StringIO#each_line.

each_codepoint {|codepoint| ... } → self Показать исходный код
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;
}

Если передан блок, вызывает его для каждой следующей кодовой точки из self; устанавливает позицию в конец потока; возвращает self.

Каждая кодовая точка — это целочисленное значение символа; возвращает 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]

Позиция в потоке имеет значение:

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

Если достигнут конец потока, блок не вызывается:

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

Если блок не передан, возвращает новый Enumerator.

Связанные методы: StringIO#each_byte, StringIO#each_char, StringIO#each_line.

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

Если передан блок, вызывает его для каждой оставшейся строки (см. раздел «Позиция» ниже) в потоке; возвращает self.

Оставляет позицию потока в конце потока.

Без аргументов

Если аргументы не переданы, читает строки, используя разделитель записей по умолчанию (глобальную переменную $/, начальное значение которой — "\n").

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

Вывод:

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

Аргумент sep

Если передан только строковый аргумент sep, читает строки, используя эту строку в качестве разделителя записей:

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

Вывод:

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

Аргумент limit

Если передан только целочисленный аргумент limit, читает строки, используя разделитель записей по умолчанию; также ограничивает размер каждой строки (в символах) заданным пределом:

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

Вывод:

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

Аргументы sep и limit

Если переданы оба аргумента — sep и limit, — учитываются оба:

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

Вывод:

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

Позиция

Как указано выше, метод each оставшуюся строку в потоке.

В примерах выше позиция каждого объекта strio находится в начале потока; в других случаях позиция может быть любой (см. StringIO#pos):

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

Вывод:

" line\n"
"Fifth line\n"

Во всех приведённых выше примерах позиция потока находится в начале символа; в других случаях это не обязательно так:

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 }

Вывод:

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

Специальные разделители записей

Как и некоторые методы класса IO, StringIO.each обрабатывает два специальных разделителя записей; см. раздел Специальные значения разделителя строк.

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

Вывод:

"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.

Вывод:

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

Именованный аргумент chomp

Если именованный аргумент chomp задан как true (значение по умолчанию — false), удаляет завершающий символ новой строки (если он есть) из каждой строки:

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

Вывод:

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

Если блок не передан, возвращает новый перечислитель.

Связанные методы: StringIO.each_byte, StringIO.each_char, StringIO.each_codepoint.

Псевдоним для: each
eof Показать исходный код
static VALUE
strio_eof(VALUE self)
{
    if (strio_to_read(self)) return Qfalse;
    return Qtrue;
}
Также имеет псевдоним: eof?
eof? → true or false

Возвращает информацию о том, находится ли self в конце потока:

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

Связанный метод: StringIO#pos.

Псевдоним для: eof
external_encoding → encoding or nil Показать исходный код
static VALUE
strio_external_encoding(VALUE self)
{
    struct StringIO *ptr = StringIO(self);
    return rb_enc_from_encoding(get_enc(ptr));
}

Возвращает объект Encoding, представляющий кодировку строки; см. раздел Кодировки:

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

Возвращает nil, если self не содержит строку и находится в режиме записи:

strio = StringIO.new(nil, 'w+')
strio.external_encoding # => nil
fcntl (*args) Показать исходный код
static VALUE
strio_unimpl(int argc, VALUE *argv, VALUE self)
{
    StringIO(self);
    rb_notimplement();

    UNREACHABLE;
}

Вызывает исключение NotImplementedError.

fileno () Показать исходный код
static VALUE
strio_nil(VALUE self)
{
    StringIO(self);
    return Qnil;
}

Возвращает nil; для совместимости с IO.

flush () Показать исходный код
static VALUE
strio_self(VALUE self)
{
    StringIO(self);
    return self;
}

Возвращает self; для совместимости с IO.

fsync () Показать исходный код
static VALUE
strio_0(VALUE self)
{
    StringIO(self);
    return INT2FIX(0);
}

Возвращает 0; для совместимости с IO.

getbyte → integer or nil Показать исходный код
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);
}

Читает и возвращает следующий целочисленный байт (не символ) из потока:

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

Возвращает nil в конце потока:

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

Возвращает байт, а не символ:

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

Связанные методы: each_byte, ungetbyte, getc.

getc → character, byte, or nil Показать исходный код
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);
}

Читает и возвращает следующий символ (или байт; см. ниже) из потока:

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

Возвращает nil в конце потока:

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

Возвращает символы, а не байты:

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

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

В каждом из приведённых выше примеров поток находится в начале символа; в других случаях это не обязательно так:

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"

Связанные методы: getbyte, putc, ungetc.

gets(sep = $/, chomp: false) → string or nil Показать исходный код
gets(limit, chomp: false) → string or nil
gets(sep, limit, chomp: false) → string or nil
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;
}

Читает и возвращает строку из потока; возвращает nil в конце потока.

Побочные эффекты:

  • Увеличивает позицию потока на число прочитанных байтов.

  • Присваивает возвращаемое значение глобальной переменной $_.

Если аргументы не указаны, читает строку, используя разделитель записей по умолчанию (глобальная переменная $/,* начальное значение которой — "\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

Аргумент sep

Если указан только строковый аргумент sep, читает строку, используя эту строку в качестве разделителя записей:

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

Аргумент limit

Если указан только целочисленный аргумент limit, читает строку, используя разделитель записей по умолчанию; ограничивает размер (в символах) каждой строки указанным значением:

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

Аргументы sep и limit

Если указаны оба аргумента — sep и limit, учитываются оба:

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

Позиция

Как указано выше, метод gets читает и возвращает следующую строку в потоке.

В примерах выше каждый объект strio начинается с позиции в начале потока; в других случаях позиция может находиться где угодно:

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

Позиция не обязательно должна находиться на границе символа:

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ивет"

Специальные разделители записей

Как и некоторые методы класса IO, метод gets учитывает два специальных разделителя записей; см. Специальные значения разделителя строк:

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"

Именованный аргумент chomp

Если именованный аргумент chomp задан как true (значение по умолчанию — false), удаляет завершающий символ новой строки (если он есть) из возвращаемой строки:

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

Связанные методы: each_line, readlines, Kernel#puts.

internal_encoding → nil Показать исходный код
static VALUE
strio_internal_encoding(VALUE self)
{
    return Qnil;
}

Возвращает nil; для совместимости с IO.

isatty () Показать исходный код
static VALUE
strio_false(VALUE self)
{
    StringIO(self);
    return Qfalse;
}

Возвращает false; для совместимости с IO.

Также имеет псевдоним: tty?
length
Псевдоним для: size
lineno → current_line_number Показать исходный код
static VALUE
strio_get_lineno(VALUE self)
{
    return LONG2NUM(StringIO(self)->lineno);
}

Возвращает текущий номер строки в self; см. Номер строки.

lineno = new_line_number → new_line_number Показать исходный код
static VALUE
strio_set_lineno(VALUE self, VALUE lineno)
{
    StringIO(self)->lineno = NUM2LONG(lineno);
    return lineno;
}

Устанавливает текущий номер строки в self в заданное значение new_line_number; см. Номер строки.

pid () Показать исходный код
static VALUE
strio_nil(VALUE self)
{
    StringIO(self);
    return Qnil;
}

Возвращает nil; для совместимости с IO.

pos → stream_position Показать исходный код
static VALUE
strio_get_pos(VALUE self)
{
    return LONG2NUM(StringIO(self)->pos);
}

Возвращает текущую позицию (в байтах); см. Позиция.

pos = new_position → new_position Показать исходный код
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;
}

Устанавливает текущую позицию (в байтах); см. Позиция.

pread(maxlen, offset) → string Показать исходный код
pread(maxlen, offset, out_string) → string
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;
}

См. IO#pread.

putc(obj) → obj Показать исходный код
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;
}

См. IO#putc.

read([length [, outbuf]]) → string, outbuf, or nil Показать исходный код
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;
}

См. IO#read.

readlines(sep=$/, chomp: false) → array Показать исходный код
readlines(limit, chomp: false) → array
readlines(sep, limit, chomp: false) → array
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;
}

См. IO#readlines.

reopen(other, mode = 'r+') → self Показать исходный код
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);
}

Повторно инициализирует поток с указанными other (строкой или StringIO) и mode; см. 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

Вывод:

"foo"
"bar"
"baz"
rewind → 0 Показать исходный код
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 Показать исходный код
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);
}

Устанавливает позицию на заданное целое число offset (в байтах) относительно заданной константы whence; см. IO#seek.

set_encoding(ext_enc, [int_enc[, opt]]) → strio Показать исходный код
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;
}

Задает кодировку StringIO как ext_enc. Если ext_enc равен nil, используется внешняя кодировка по умолчанию. Второй аргумент int_enc и необязательный аргумент-хеш opt игнорируются; они предусмотрены для совместимости API с IO.

set_encoding_by_bom → strio or nil Показать исходный код
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);
}

Устанавливает кодировку в соответствии с BOM (маркером порядка байтов) в строке.

Возвращает self, если BOM найден, в противном случае — +nil.

size → integer Показать исходный код
static VALUE
strio_size(VALUE self)
{
    VALUE string = StringIO(self)->string;
    if (NIL_P(string)) {
        return INT2FIX(0);
    }
    return ULONG2NUM(RSTRING_LEN(string));
}

Возвращает количество байтов в строке в 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.
Также имеет псевдоним: length
string → string Показать исходный код
static VALUE
strio_get_string(VALUE self)
{
    return StringIO(self)->string;
}

Возвращает базовую строку:

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

Вывод:

"foo"
"bar"

Связанный метод: StringIO#string= (назначает базовую строку).

string = other_string → other_string Показать исходный код
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;
}

Заменяет сохраненную строку на other_string и устанавливает позицию в ноль; возвращает other_string:

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

Вывод:

"foo"
"bar"

Связанный метод: StringIO#string (возвращает сохраненную строку).

sync → true Показать исходный код
static VALUE
strio_get_sync(VALUE self)
{
    StringIO(self);
    return Qtrue;
}

Возвращает true; реализован только для совместимости с другими классами потоков.

sync= (p1) Показать исходный код
static VALUE
strio_first(VALUE self, VALUE arg)
{
    StringIO(self);
    return arg;
}

Возвращает аргумент без изменений. Предусмотрен только для совместимости с IO.

pos → stream_position Показать исходный код
static VALUE
strio_get_pos(VALUE self)
{
    return LONG2NUM(StringIO(self)->pos);
}

Возвращает текущую позицию (в байтах); см. Позиция.

truncate(integer) → 0 Показать исходный код
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);
}

Обрезает строку буфера до длины не более integer байтов. Поток должен быть открыт для записи.

tty? ()

Возвращает false; предусмотрен для совместимости с IO.

Псевдоним для: isatty
ungetbyte(byte) → nil Показать исходный код
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;
}

Возвращает 8-битный байт в поток («сдвигает его обратно»); см. Ввод-вывод байтов.

ungetc(character) → nil Показать исходный код
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
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);
}

Добавляет заданную строку в базовую строку буфера. Поток должен быть открыт для записи. Если аргумент не является строкой, он будет преобразован в строку с помощью to_s. Возвращает количество записанных байтов. См. IO#write.

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API