класс StringIO
Псевдо-Ввод/Вывод для объекта String, с интерфейсом, соответствующим IO.
Часто используется для моделирования $stdio или $stderr
Примеры
require 'stringio' # Writing stream emulation io = StringIO.new io.puts "Hello World" io.string #=> "Hello World\n" # Reading stream emulation io = StringIO.new "first\nsecond\nlast\n" io.getc #=> "f" io.gets #=> "irst\n" io.read #=> "second\nlast\n"
Константы
- VERSION
Публичные методы класса
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.
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.new, за исключением того, что при вызове с блоком, передаёт новый экземпляр и закрывает его, возвращая результат, полученный от блока.
Общедоступные методы экземпляров
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;
} Переводит поток в двоичный режим. См. IO#binmode.
static VALUE
strio_close(VALUE self)
{
StringIO(self);
RBASIC(self)->flags &= ~STRIO_READWRITE;
return Qnil;
} Закрывает StringIO. Поток недоступен для дальнейших операций с данными; попытка выполнить такие операции вызовет IOError.
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;
} Закрывает конец для чтения StringIO. Вызовет IOError если объект не читаем.
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;
} Закрывает конец для записи StringIO. Вызовет IOError если объект не записываем.
static VALUE
strio_closed(VALUE self)
{
StringIO(self);
if (!CLOSED(self)) return Qfalse;
return Qtrue;
} Возвращает true если поток полностью закрыт, false в противном случае.
static VALUE
strio_closed_read(VALUE self)
{
StringIO(self);
if (READABLE(self)) return Qfalse;
return Qtrue;
} Возвращает true если поток не читаем, false в противном случае.
static VALUE
strio_closed_write(VALUE self)
{
StringIO(self);
if (WRITABLE(self)) return Qfalse;
return Qtrue;
} Возвращает true если поток не записываем, false в противном случае.
static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
{
VALUE line;
struct getline_arg arg;
StringIO(self);
RETURN_ENUMERATOR(self, argc, argv);
if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
}
while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
rb_yield(line);
}
return self;
} См. IO#each.
static VALUE
strio_each_byte(VALUE self)
{
struct StringIO *ptr = readable(self);
RETURN_ENUMERATOR(self, 0, 0);
while (ptr->pos < RSTRING_LEN(ptr->string)) {
char c = RSTRING_PTR(ptr->string)[ptr->pos++];
rb_yield(CHR2FIX(c));
}
return self;
} См. IO#each_byte.
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;
} См. IO#each_char.
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);
for (;;) {
if (ptr->pos >= RSTRING_LEN(ptr->string)) {
return self;
}
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;
} См. IO#each_codepoint.
static VALUE
strio_eof(VALUE self)
{
struct StringIO *ptr = readable(self);
if (ptr->pos < RSTRING_LEN(ptr->string)) return Qfalse;
return Qtrue;
} Возвращает true, если поток достиг конца данных (основанного на строке). Поток должен быть открыт для чтения, иначе произойдёт IOError.
Возвращает true, если поток достиг конца данных (основанного на строке). Поток должен быть открыт для чтения, иначе произойдёт IOError.
static VALUE
strio_external_encoding(VALUE self)
{
struct StringIO *ptr = StringIO(self);
return rb_enc_from_encoding(get_enc(ptr));
} Возвращает объект Encoding, представляющий кодировку файла. Если поток в режиме записи и кодировка не указана, возвращает nil.
static VALUE
strio_unimpl(int argc, VALUE *argv, VALUE self)
{
StringIO(self);
rb_notimplement();
UNREACHABLE;
} Вызывает NotImplementedError.
static VALUE
strio_nil(VALUE self)
{
StringIO(self);
return Qnil;
} Возвращает nil. Просто для совместимости с IO.
static VALUE
strio_self(VALUE self)
{
StringIO(self);
return self;
} Возвращает сам объект. Просто для совместимости с IO.
static VALUE
strio_0(VALUE self)
{
StringIO(self);
return INT2FIX(0);
} Возвращает 0. Просто для совместимости с IO.
static VALUE
strio_getbyte(VALUE self)
{
struct StringIO *ptr = readable(self);
int c;
if (ptr->pos >= RSTRING_LEN(ptr->string)) {
return Qnil;
}
c = RSTRING_PTR(ptr->string)[ptr->pos++];
return CHR2FIX(c);
} См. IO#getbyte.
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 (pos >= RSTRING_LEN(str)) {
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);
} См. IO#getc.
static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
{
struct getline_arg arg;
VALUE str;
if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
struct StringIO *ptr = readable(self);
return rb_enc_str_new(0, 0, get_enc(ptr));
}
str = strio_getline(&arg, readable(self));
rb_lastline_set(str);
return str;
} См. IO#gets.
static VALUE
strio_internal_encoding(VALUE self)
{
return Qnil;
} Возвращает Encoding внутренней строки, если преобразование указано. В противном случае возвращает nil.
static VALUE
strio_get_lineno(VALUE self)
{
return LONG2NUM(StringIO(self)->lineno);
} Возвращает текущий номер строки. Поток должен быть открыт для чтения. lineno подсчитывает количество вызовов gets, а не количество символов новой строки. Два значения будут отличаться, если gets вызывается с разделителем, отличным от новой строки. Смотрите также переменную $..
static VALUE
strio_set_lineno(VALUE self, VALUE lineno)
{
StringIO(self)->lineno = NUM2LONG(lineno);
return lineno;
} Вручную устанавливает текущий номер строки на заданное значение. $. обновляется только при следующем чтении.
static VALUE
strio_nil(VALUE self)
{
StringIO(self);
return Qnil;
} Возвращает nil. Только для совместимости с IO.
static VALUE
strio_get_pos(VALUE self)
{
return LONG2NUM(StringIO(self)->pos);
} Возвращает текущее смещение (в байтах).
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;
} Перемещает указатель на заданную позицию (в байтах).
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)) {
str = rb_str_substr(ch, 0, 1);
}
else {
char c = NUM2CHR(ch);
str = rb_str_new(&c, 1);
}
strio_write(self, str);
return ch;
} См. IO#putc.
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 (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
if (!NIL_P(str)) rb_str_resize(str, 0);
return Qnil;
}
binary = 1;
break;
}
/* fall through */
case 0:
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_associate(str, rb_ascii8bit_encoding());
else
rb_enc_copy(str, ptr->string);
}
ptr->pos += RSTRING_LEN(str);
return str;
} См. IO#read.
static VALUE
strio_readlines(int argc, VALUE *argv, VALUE self)
{
VALUE ary, line;
struct getline_arg arg;
StringIO(self);
ary = rb_ary_new();
if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
}
while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
rb_ary_push(ary, line);
}
return ary;
} См. IO#readlines.
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_StrIO или строкой и режимом (см. StringIO#new).
static VALUE
strio_rewind(VALUE self)
{
struct StringIO *ptr = StringIO(self);
ptr->pos = 0;
ptr->lineno = 0;
return INT2FIX(0);
} Позиционирует поток в начало входных данных, сбрасывая lineno до нуля.
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:
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);
} Перемещает указатель на заданное смещение значение в потоке в соответствии со значением откуда (см. IO#seek).
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_to_encoding(ext_enc);
}
ptr->enc = enc;
if (WRITABLE(self)) {
rb_enc_associate(ptr->string, enc);
}
return self;
} Укажите кодировку StringIO как внешний_код. Используйте стандартную внешнюю кодировку, если внешний_код равно nil. 2-й аргумент внутренний_код и необязательный аргумент опции игнорируются; они предназначены для совместимости с API IO.
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);
} static VALUE
strio_size(VALUE self)
{
VALUE string = StringIO(self)->string;
if (NIL_P(string)) {
rb_raise(rb_eIOError, "not opened");
}
return ULONG2NUM(RSTRING_LEN(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 = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
ptr->pos = 0;
ptr->lineno = 0;
return ptr->string = string;
} static VALUE
strio_get_sync(VALUE self)
{
StringIO(self);
return Qtrue;
} Возвращает true всегда.
static VALUE
strio_first(VALUE self, VALUE arg)
{
StringIO(self);
return arg;
} Возвращает аргумент без изменений. Только для совместимости с IO.
static VALUE
strio_get_pos(VALUE self)
{
return LONG2NUM(StringIO(self)->pos);
} Возвращает текущее смещение (в байтах).
static VALUE
strio_truncate(VALUE self, VALUE len)
{
VALUE string = writable(self)->string;
long l = NUM2LONG(len);
long plen = RSTRING_LEN(string);
if (l < 0) {
error_inval("negative length");
}
rb_str_resize(string, l);
if (plen < l) {
MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
}
return len;
} Усекает буферную строку до не более чем целое байт. Поток должен быть открыт для записи.
static VALUE
strio_ungetbyte(VALUE self, VALUE c)
{
struct StringIO *ptr = readable(self);
check_modifiable(ptr);
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 {
long cl;
SafeStringValue(c);
cl = RSTRING_LEN(c);
if (cl > 0) {
strio_unget_bytes(ptr, RSTRING_PTR(c), cl);
RB_GC_GUARD(c);
}
}
return Qnil;
} См. IO#ungetbyte
static VALUE
strio_ungetc(VALUE self, VALUE c)
{
struct StringIO *ptr = readable(self);
rb_encoding *enc, *enc2;
check_modifiable(ptr);
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);
rb_enc_mbcput(cc, buf, enc);
return strio_unget_bytes(ptr, buf, len);
}
else {
SafeStringValue(c);
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_bytes(ptr, RSTRING_PTR(c), RSTRING_LEN(c));
RB_GC_GUARD(c);
return Qnil;
}
} Возвращает один символ (переданный в качестве параметра) таким образом, что последующее буферизованное чтение вернёт его. Нет ограничений на количество обратных записей, включая записи позади начала буферной строки.
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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.