stringio 3.1.6 → 3.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 144b6bb8aaa29ad8b3447e979841af712093bdfe19623f26d46a595740541da6
4
- data.tar.gz: a0936d98e00b6dec96769e8189b564fee83d922a7d7f2787fa58b15e648ff22f
3
+ metadata.gz: 7955baf0f07b14461ca7f88b4c2f97383d9cf1114e07fd7408e1e332f974c139
4
+ data.tar.gz: 4169d5e9055f8ce90725fc374030ff97b8473734741c3cb741527f7e0aefd865
5
5
  SHA512:
6
- metadata.gz: 3c49d46b584a010121a0c20a176a1e389178f8e53810d9898107c28154116519caf8883d68339a69a580b684f236854c36eecd4562182bf1724e67d951351a05
7
- data.tar.gz: 69189970d83c1093020071a1c86c7eb60067b06e0500b112aa55c82ad97a95ad4ba66ce7f08c018ae58312a662a9cc55de59129c5d6ebcad93c2ec9c5927ed98
6
+ metadata.gz: e91d6fa5462e3afec46f4e709dd746e8bb275198825eca723634b2837207270c05973f224884525da256fd1ad17b1da7659046f78135ba958651715c7a34b5f7
7
+ data.tar.gz: 673e6b9e4e59a31b708963893bcc9ea80e01351b272b82992467b72e8c7a074eb9f2f8f854cbdc2767ca826c5d9351cfaa82ce721e8a32dca41ca6ad9a47f883
data/.rdoc_options CHANGED
@@ -1,2 +1,5 @@
1
1
  ---
2
2
  main_page: README.md
3
+ rdoc_include:
4
+ - doc
5
+ op_dir: html
data/NEWS.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # News
2
2
 
3
+ ## 3.1.8 - 2025-11-12
4
+
5
+ ### Improvements
6
+
7
+ * Improved documents
8
+ * Patch by Burdette Lamar
9
+
10
+ ### Fixes
11
+
12
+ * Fixed SEGV in `StringIO#seek` with `SEEK_END` on `StringIO.new(nil)`
13
+ * GH-137
14
+ * Patch by koh-sh
15
+
16
+ * Fixed SEGV in `StringIO#read` on `StringIO.new(nil)`
17
+
18
+ * Fixed SEGV in `StringIO#pread` on `StringIO.new(nil)`
19
+
20
+ * Fixed SEGV in `StringIO#eof?` on `StringIO.new(nil)`
21
+
22
+ * JRuby: Fixed a bug that `StringIO#read` doesn't clear code range
23
+ * GH-156
24
+ * Patch by Karol Bucek
25
+
26
+ ### Thanks
27
+
28
+ * koh-sh
29
+
30
+ * Burdette Lamar
31
+
32
+ * Karol Bucek
33
+
34
+ ## 3.1.7 - 2025-04-21
35
+
36
+ ### Improvements
37
+
38
+ * CRuby: Added support for `rb_io_mode_t` that will be introduced in
39
+ Ruby 3.5 or later.
40
+ * GH-129
41
+ * Patch by Samuel Williams
42
+
43
+ ### Thanks
44
+
45
+ * Samuel Williams
46
+
3
47
  ## 3.1.6 - 2025-03-25
4
48
 
5
49
  ### Fixes
data/docs/io.rb CHANGED
@@ -1,8 +1,3 @@
1
- # :stopdoc:
1
+ # The {built-in class for I/O}[https://docs.ruby-lang.org/en/master/IO.html].
2
2
  class IO
3
- module generic_readable
4
- end
5
- module generic_writable
6
- end
7
3
  end
8
- # :startdoc:
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  require 'mkmf'
3
3
  if RUBY_ENGINE == 'ruby'
4
+ have_type("rb_io_mode_t", "ruby/io.h")
5
+
4
6
  create_makefile('stringio')
5
7
  else
6
8
  File.write('Makefile', dummy_makefile("").join)
@@ -13,13 +13,14 @@
13
13
  **********************************************************************/
14
14
 
15
15
  static const char *const
16
- STRINGIO_VERSION = "3.1.6";
16
+ STRINGIO_VERSION = "3.1.8";
17
17
 
18
18
  #include <stdbool.h>
19
19
 
20
20
  #include "ruby.h"
21
21
  #include "ruby/io.h"
22
22
  #include "ruby/encoding.h"
23
+ #include "ruby/version.h"
23
24
  #if defined(HAVE_FCNTL_H) || defined(_WIN32)
24
25
  #include <fcntl.h>
25
26
  #elif defined(HAVE_SYS_FCNTL_H)
@@ -35,12 +36,29 @@ STRINGIO_VERSION = "3.1.6";
35
36
  # define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
36
37
  #endif
37
38
 
39
+ static inline bool
40
+ str_chilled_p(VALUE str)
41
+ {
42
+ #if (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 4) || RUBY_API_VERSION_MAJOR >= 4
43
+ // Do not attempt to modify chilled strings on Ruby 3.4+
44
+ // RUBY_FL_USER2 == STR_CHILLED_LITERAL
45
+ // RUBY_FL_USER3 == STR_CHILLED_SYMBOL_TO_S
46
+ return FL_TEST_RAW(str, RUBY_FL_USER2 | RUBY_FL_USER3);
47
+ #else
48
+ return false;
49
+ #endif
50
+ }
51
+
52
+ #ifndef HAVE_TYPE_RB_IO_MODE_T
53
+ typedef int rb_io_mode_t;
54
+ #endif
55
+
38
56
  struct StringIO {
39
57
  VALUE string;
40
58
  rb_encoding *enc;
41
59
  long pos;
42
60
  long lineno;
43
- int flags;
61
+ rb_io_mode_t flags;
44
62
  int count;
45
63
  };
46
64
 
@@ -185,6 +203,18 @@ check_modifiable(struct StringIO *ptr)
185
203
  }
186
204
  }
187
205
 
206
+ static inline bool
207
+ outside_p(struct StringIO *ptr, long pos)
208
+ {
209
+ return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
210
+ }
211
+
212
+ static inline bool
213
+ eos_p(struct StringIO *ptr)
214
+ {
215
+ return outside_p(ptr, ptr->pos);
216
+ }
217
+
188
218
  static VALUE
189
219
  strio_s_allocate(VALUE klass)
190
220
  {
@@ -195,17 +225,32 @@ strio_s_allocate(VALUE klass)
195
225
  * call-seq:
196
226
  * StringIO.new(string = '', mode = 'r+') -> new_stringio
197
227
  *
198
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
199
- *
200
228
  * Returns a new \StringIO instance formed from +string+ and +mode+;
201
- * see {Access Modes}[rdoc-ref:File@Access+Modes]:
229
+ * the instance should be closed when no longer needed:
230
+ *
231
+ * strio = StringIO.new
232
+ * strio.string # => ""
233
+ * strio.closed_read? # => false
234
+ * strio.closed_write? # => false
235
+ * strio.close
202
236
  *
203
- * strio = StringIO.new # => #<StringIO>
237
+ * If +string+ is frozen, the default +mode+ is <tt>'r'</tt>:
238
+ *
239
+ * strio = StringIO.new('foo'.freeze)
240
+ * strio.string # => "foo"
241
+ * strio.closed_read? # => false
242
+ * strio.closed_write? # => true
204
243
  * strio.close
205
244
  *
206
- * The instance should be closed when no longer needed.
245
+ * Argument +mode+ must be a valid
246
+ * {Access Mode}[https://docs.ruby-lang.org/en/master/File.html#class-File-label-Access+Modes],
247
+ * which may be a string or an integer constant:
248
+ *
249
+ * StringIO.new('foo', 'w+')
250
+ * StringIO.new('foo', File::RDONLY)
207
251
  *
208
- * Related: StringIO.open (accepts block; closes automatically).
252
+ * Related: StringIO.open
253
+ * (passes the \StringIO object to the block; closes the object automatically on block exit).
209
254
  */
210
255
  static VALUE
211
256
  strio_initialize(int argc, VALUE *argv, VALUE self)
@@ -340,23 +385,20 @@ strio_finalize(VALUE self)
340
385
 
341
386
  /*
342
387
  * call-seq:
343
- * StringIO.open(string = '', mode = 'r+') {|strio| ... }
344
- *
345
- * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
388
+ * StringIO.open(string = '', mode = 'r+') -> new_stringio
389
+ * StringIO.open(string = '', mode = 'r+') {|strio| ... } -> object
346
390
  *
347
- * Creates a new \StringIO instance formed from +string+ and +mode+;
348
- * see {Access Modes}[rdoc-ref:File@Access+Modes].
391
+ * Creates new \StringIO instance by calling <tt>StringIO.new(string, mode)</tt>.
349
392
  *
350
- * With no block, returns the new instance:
393
+ * With no block given, returns the new instance:
351
394
  *
352
395
  * strio = StringIO.open # => #<StringIO>
353
396
  *
354
- * With a block, calls the block with the new instance
397
+ * With a block given, calls the block with the new instance
355
398
  * and returns the block's value;
356
- * closes the instance on block exit.
399
+ * closes the instance on block exit:
357
400
  *
358
- * StringIO.open {|strio| p strio }
359
- * # => #<StringIO>
401
+ * StringIO.open('foo') {|strio| strio.string.upcase } # => "FOO"
360
402
  *
361
403
  * Related: StringIO.new.
362
404
  */
@@ -382,7 +424,7 @@ strio_s_new(int argc, VALUE *argv, VALUE klass)
382
424
  }
383
425
 
384
426
  /*
385
- * Returns +false+. Just for compatibility to IO.
427
+ * Returns +false+; for compatibility with IO.
386
428
  */
387
429
  static VALUE
388
430
  strio_false(VALUE self)
@@ -392,7 +434,7 @@ strio_false(VALUE self)
392
434
  }
393
435
 
394
436
  /*
395
- * Returns +nil+. Just for compatibility to IO.
437
+ * Returns +nil+; for compatibility with IO.
396
438
  */
397
439
  static VALUE
398
440
  strio_nil(VALUE self)
@@ -402,7 +444,7 @@ strio_nil(VALUE self)
402
444
  }
403
445
 
404
446
  /*
405
- * Returns an object itself. Just for compatibility to IO.
447
+ * Returns +self+; for compatibility with IO.
406
448
  */
407
449
  static VALUE
408
450
  strio_self(VALUE self)
@@ -412,7 +454,7 @@ strio_self(VALUE self)
412
454
  }
413
455
 
414
456
  /*
415
- * Returns 0. Just for compatibility to IO.
457
+ * Returns 0; for compatibility with IO.
416
458
  */
417
459
  static VALUE
418
460
  strio_0(VALUE self)
@@ -472,7 +514,7 @@ strio_get_string(VALUE self)
472
514
  * call-seq:
473
515
  * string = other_string -> other_string
474
516
  *
475
- * Assigns the underlying string as +other_string+, and sets position to zero;
517
+ * Replaces the stored string with +other_string+, and sets the position to zero;
476
518
  * returns +other_string+:
477
519
  *
478
520
  * StringIO.open('foo') do |strio|
@@ -486,7 +528,7 @@ strio_get_string(VALUE self)
486
528
  * "foo"
487
529
  * "bar"
488
530
  *
489
- * Related: StringIO#string (returns the underlying string).
531
+ * Related: StringIO#string (returns the stored string).
490
532
  */
491
533
  static VALUE
492
534
  strio_set_string(VALUE self, VALUE string)
@@ -507,11 +549,16 @@ strio_set_string(VALUE self, VALUE string)
507
549
  * call-seq:
508
550
  * close -> nil
509
551
  *
510
- * Closes +self+ for both reading and writing.
552
+ * Closes +self+ for both reading and writing; returns +nil+:
511
553
  *
512
- * Raises IOError if reading or writing is attempted.
554
+ * strio = StringIO.new
555
+ * strio.closed? # => false
556
+ * strio.close # => nil
557
+ * strio.closed? # => true
558
+ * strio.read # Raises IOError: not opened for reading
559
+ * strio.write # Raises IOError: not opened for writing
513
560
  *
514
- * Related: StringIO#close_read, StringIO#close_write.
561
+ * Related: StringIO#close_read, StringIO#close_write, StringIO.closed?.
515
562
  */
516
563
  static VALUE
517
564
  strio_close(VALUE self)
@@ -525,9 +572,16 @@ strio_close(VALUE self)
525
572
  * call-seq:
526
573
  * close_read -> nil
527
574
  *
528
- * Closes +self+ for reading; closed-write setting remains unchanged.
575
+ * Closes +self+ for reading;
576
+ * closed-write setting remains unchanged;
577
+ * returns +nil+:
529
578
  *
530
- * Raises IOError if reading is attempted.
579
+ * strio = StringIO.new
580
+ * strio.closed_read? # => false
581
+ * strio.close_read # => nil
582
+ * strio.closed_read? # => true
583
+ * strio.closed_write? # => false
584
+ * strio.read # Raises IOError: not opened for reading
531
585
  *
532
586
  * Related: StringIO#close, StringIO#close_write.
533
587
  */
@@ -546,11 +600,16 @@ strio_close_read(VALUE self)
546
600
  * call-seq:
547
601
  * close_write -> nil
548
602
  *
549
- * Closes +self+ for writing; closed-read setting remains unchanged.
603
+ * Closes +self+ for writing; closed-read setting remains unchanged; returns +nil+:
550
604
  *
551
- * Raises IOError if writing is attempted.
605
+ * strio = StringIO.new
606
+ * strio.closed_write? # => false
607
+ * strio.close_write # => nil
608
+ * strio.closed_write? # => true
609
+ * strio.closed_read? # => false
610
+ * strio.write('foo') # Raises IOError: not opened for writing
552
611
  *
553
- * Related: StringIO#close, StringIO#close_read.
612
+ * Related: StringIO#close, StringIO#close_read, StringIO#closed_write?.
554
613
  */
555
614
  static VALUE
556
615
  strio_close_write(VALUE self)
@@ -567,8 +626,16 @@ strio_close_write(VALUE self)
567
626
  * call-seq:
568
627
  * closed? -> true or false
569
628
  *
570
- * Returns +true+ if +self+ is closed for both reading and writing,
571
- * +false+ otherwise.
629
+ * Returns whether +self+ is closed for both reading and writing:
630
+ *
631
+ * strio = StringIO.new
632
+ * strio.closed? # => false # Open for reading and writing.
633
+ * strio.close_read
634
+ * strio.closed? # => false # Still open for writing.
635
+ * strio.close_write
636
+ * strio.closed? # => true # Now closed for both.
637
+ *
638
+ * Related: StringIO.closed_read?, StringIO.closed_write?.
572
639
  */
573
640
  static VALUE
574
641
  strio_closed(VALUE self)
@@ -582,7 +649,14 @@ strio_closed(VALUE self)
582
649
  * call-seq:
583
650
  * closed_read? -> true or false
584
651
  *
585
- * Returns +true+ if +self+ is closed for reading, +false+ otherwise.
652
+ * Returns whether +self+ is closed for reading:
653
+ *
654
+ * strio = StringIO.new
655
+ * strio.closed_read? # => false
656
+ * strio.close_read
657
+ * strio.closed_read? # => true
658
+ *
659
+ * Related: StringIO#closed?, StringIO#closed_write?, StringIO#close_read.
586
660
  */
587
661
  static VALUE
588
662
  strio_closed_read(VALUE self)
@@ -596,7 +670,14 @@ strio_closed_read(VALUE self)
596
670
  * call-seq:
597
671
  * closed_write? -> true or false
598
672
  *
599
- * Returns +true+ if +self+ is closed for writing, +false+ otherwise.
673
+ * Returns whether +self+ is closed for writing:
674
+ *
675
+ * strio = StringIO.new
676
+ * strio.closed_write? # => false
677
+ * strio.close_write
678
+ * strio.closed_write? # => true
679
+ *
680
+ * Related: StringIO#close_write, StringIO#closed?, StringIO#closed_read?.
600
681
  */
601
682
  static VALUE
602
683
  strio_closed_write(VALUE self)
@@ -610,19 +691,26 @@ static struct StringIO *
610
691
  strio_to_read(VALUE self)
611
692
  {
612
693
  struct StringIO *ptr = readable(self);
613
- if (NIL_P(ptr->string)) return NULL;
614
- if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
615
- return NULL;
694
+ if (eos_p(ptr)) return NULL;
695
+ return ptr;
616
696
  }
617
697
 
618
698
  /*
619
699
  * call-seq:
620
700
  * eof? -> true or false
621
701
  *
622
- * Returns +true+ if positioned at end-of-stream, +false+ otherwise;
623
- * see {Position}[rdoc-ref:IO@Position].
702
+ * Returns whether +self+ is positioned at end-of-stream:
703
+ *
704
+ * strio = StringIO.new('foo')
705
+ * strio.pos # => 0
706
+ * strio.eof? # => false
707
+ * strio.read # => "foo"
708
+ * strio.pos # => 3
709
+ * strio.eof? # => true
710
+ * strio.close_read
711
+ * strio.eof? # Raises IOError: not opened for reading
624
712
  *
625
- * Raises IOError if the stream is not opened for reading.
713
+ * Related: StringIO#pos.
626
714
  */
627
715
  static VALUE
628
716
  strio_eof(VALUE self)
@@ -686,7 +774,7 @@ strio_set_lineno(VALUE self, VALUE lineno)
686
774
  * binmode -> self
687
775
  *
688
776
  * Sets the data mode in +self+ to binary mode;
689
- * see {Data Mode}[rdoc-ref:File@Data+Mode].
777
+ * see {Data Mode}[https://docs.ruby-lang.org/en/master/File.html#class-File-label-Data+Mode].
690
778
  *
691
779
  */
692
780
  static VALUE
@@ -819,7 +907,11 @@ strio_seek(int argc, VALUE *argv, VALUE self)
819
907
  offset = ptr->pos;
820
908
  break;
821
909
  case 2:
822
- offset = RSTRING_LEN(ptr->string);
910
+ if (NIL_P(ptr->string)) {
911
+ offset = 0;
912
+ } else {
913
+ offset = RSTRING_LEN(ptr->string);
914
+ }
823
915
  break;
824
916
  default:
825
917
  error_inval("invalid whence");
@@ -852,10 +944,9 @@ strio_get_sync(VALUE self)
852
944
  * call-seq:
853
945
  * each_byte {|byte| ... } -> self
854
946
  *
855
- * With a block given, calls the block with each remaining byte in the stream;
856
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
947
+ * :include: stringio/each_byte.rdoc
857
948
  *
858
- * With no block given, returns an enumerator.
949
+ * Related: StringIO#each_char, StringIO#each_codepoint, StringIO#each_line.
859
950
  */
860
951
  static VALUE
861
952
  strio_each_byte(VALUE self)
@@ -873,10 +964,10 @@ strio_each_byte(VALUE self)
873
964
 
874
965
  /*
875
966
  * call-seq:
876
- * getc -> character or nil
967
+ * getc -> character, byte, or nil
968
+ *
969
+ * :include: stringio/getc.rdoc
877
970
  *
878
- * Reads and returns the next character from the stream;
879
- * see {Character IO}[rdoc-ref:IO@Character+IO].
880
971
  */
881
972
  static VALUE
882
973
  strio_getc(VALUE self)
@@ -888,7 +979,7 @@ strio_getc(VALUE self)
888
979
  int len;
889
980
  char *p;
890
981
 
891
- if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
982
+ if (eos_p(ptr)) {
892
983
  return Qnil;
893
984
  }
894
985
  p = RSTRING_PTR(str)+pos;
@@ -899,17 +990,17 @@ strio_getc(VALUE self)
899
990
 
900
991
  /*
901
992
  * call-seq:
902
- * getbyte -> byte or nil
993
+ * getbyte -> integer or nil
994
+ *
995
+ * :include: stringio/getbyte.rdoc
903
996
  *
904
- * Reads and returns the next 8-bit byte from the stream;
905
- * see {Byte IO}[rdoc-ref:IO@Byte+IO].
906
997
  */
907
998
  static VALUE
908
999
  strio_getbyte(VALUE self)
909
1000
  {
910
1001
  struct StringIO *ptr = readable(self);
911
1002
  int c;
912
- if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
1003
+ if (eos_p(ptr)) {
913
1004
  return Qnil;
914
1005
  }
915
1006
  c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -1078,12 +1169,11 @@ strio_readbyte(VALUE self)
1078
1169
 
1079
1170
  /*
1080
1171
  * call-seq:
1081
- * each_char {|c| ... } -> self
1172
+ * each_char {|char| ... } -> self
1082
1173
  *
1083
- * With a block given, calls the block with each remaining character in the stream;
1084
- * see {Character IO}[rdoc-ref:IO@Character+IO].
1174
+ * :include: stringio/each_char.rdoc
1085
1175
  *
1086
- * With no block given, returns an enumerator.
1176
+ * Related: StringIO#each_byte, StringIO#each_codepoint, StringIO#each_line.
1087
1177
  */
1088
1178
  static VALUE
1089
1179
  strio_each_char(VALUE self)
@@ -1102,10 +1192,9 @@ strio_each_char(VALUE self)
1102
1192
  * call-seq:
1103
1193
  * each_codepoint {|codepoint| ... } -> self
1104
1194
  *
1105
- * With a block given, calls the block with each remaining codepoint in the stream;
1106
- * see {Codepoint IO}[rdoc-ref:IO@Codepoint+IO].
1195
+ * :include: stringio/each_codepoint.rdoc
1107
1196
  *
1108
- * With no block given, returns an enumerator.
1197
+ * Related: StringIO#each_byte, StringIO#each_char, StringIO#each_line.
1109
1198
  */
1110
1199
  static VALUE
1111
1200
  strio_each_codepoint(VALUE self)
@@ -1339,9 +1428,8 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
1339
1428
  * gets(limit, chomp: false) -> string or nil
1340
1429
  * gets(sep, limit, chomp: false) -> string or nil
1341
1430
  *
1342
- * Reads and returns a line from the stream;
1343
- * assigns the return value to <tt>$_</tt>;
1344
- * see {Line IO}[rdoc-ref:IO@Line+IO].
1431
+ * :include: stringio/gets.rdoc
1432
+ *
1345
1433
  */
1346
1434
  static VALUE
1347
1435
  strio_gets(int argc, VALUE *argv, VALUE self)
@@ -1378,15 +1466,177 @@ strio_readline(int argc, VALUE *argv, VALUE self)
1378
1466
  }
1379
1467
 
1380
1468
  /*
1469
+ * :markup: markdown
1470
+ *
1381
1471
  * call-seq:
1382
1472
  * each_line(sep = $/, chomp: false) {|line| ... } -> self
1383
1473
  * each_line(limit, chomp: false) {|line| ... } -> self
1384
1474
  * each_line(sep, limit, chomp: false) {|line| ... } -> self
1385
1475
  *
1386
- * Calls the block with each remaining line read from the stream;
1387
- * does nothing if already at end-of-file;
1388
- * returns +self+.
1389
- * See {Line IO}[rdoc-ref:IO@Line+IO].
1476
+ * With a block given calls the block with each remaining line (see "Position" below) in the stream;
1477
+ * returns `self`.
1478
+ *
1479
+ * Leaves stream position as end-of-stream.
1480
+ *
1481
+ * **No Arguments**
1482
+ *
1483
+ * With no arguments given,
1484
+ * reads lines using the default record separator global variable `$/`, whose initial value is `"\n"`.
1485
+ *
1486
+ * ```
1487
+ * strio = StringIO.new(TEXT)
1488
+ * strio.each_line {|line| p line }
1489
+ * strio.eof? # => true
1490
+ * ```
1491
+ *
1492
+ * Output:
1493
+ *
1494
+ * ```
1495
+ * "First line\n"
1496
+ * "Second line\n"
1497
+ * "\n"
1498
+ * "Fourth line\n"
1499
+ * "Fifth line\n"
1500
+ * ```
1501
+ *
1502
+ * **Argument `sep`**
1503
+ *
1504
+ * With only string argument `sep` given,
1505
+ * reads lines using that string as the record separator:
1506
+ *
1507
+ * ```
1508
+ * strio = StringIO.new(TEXT)
1509
+ * strio.each_line(' ') {|line| p line }
1510
+ * ```
1511
+ *
1512
+ * Output:
1513
+ *
1514
+ * ```
1515
+ * "First "
1516
+ * "line\nSecond "
1517
+ * "line\n\nFourth "
1518
+ * "line\nFifth "
1519
+ * "line\n"
1520
+ * ```
1521
+ *
1522
+ * **Argument `limit`**
1523
+ *
1524
+ * With only integer argument `limit` given,
1525
+ * reads lines using the default record separator global variable `$/`, whose initial value is `"\n"`;
1526
+ * also limits the size (in characters) of each line to the given limit:
1527
+ *
1528
+ * ```
1529
+ * strio = StringIO.new(TEXT)
1530
+ * strio.each_line(10) {|line| p line }
1531
+ * ```
1532
+ *
1533
+ * Output:
1534
+ *
1535
+ * ```
1536
+ * "First line"
1537
+ * "\n"
1538
+ * "Second lin"
1539
+ * "e\n"
1540
+ * "\n"
1541
+ * "Fourth lin"
1542
+ * "e\n"
1543
+ * "Fifth line"
1544
+ * "\n"
1545
+ * ```
1546
+ * **Arguments `sep` and `limit`**
1547
+ *
1548
+ * With arguments `sep` and `limit` both given,
1549
+ * honors both:
1550
+ *
1551
+ * ```
1552
+ * strio = StringIO.new(TEXT)
1553
+ * strio.each_line(' ', 10) {|line| p line }
1554
+ * ```
1555
+ *
1556
+ * Output:
1557
+ *
1558
+ * ```
1559
+ * "First "
1560
+ * "line\nSecon"
1561
+ * "d "
1562
+ * "line\n\nFour"
1563
+ * "th "
1564
+ * "line\nFifth"
1565
+ * " "
1566
+ * "line\n"
1567
+ * ```
1568
+ *
1569
+ * **Position**
1570
+ *
1571
+ * As stated above, method `each` _remaining_ line in the stream.
1572
+ *
1573
+ * In the examples above each `strio` object starts with its position at beginning-of-stream;
1574
+ * but in other cases the position may be anywhere (see StringIO#pos):
1575
+ *
1576
+ * ```
1577
+ * strio = StringIO.new(TEXT)
1578
+ * strio.pos = 30 # Set stream position to character 30.
1579
+ * strio.each_line {|line| p line }
1580
+ * ```
1581
+ *
1582
+ * Output:
1583
+ *
1584
+ * ```
1585
+ * " line\n"
1586
+ * "Fifth line\n"
1587
+ * ```
1588
+ *
1589
+ * **Special Record Separators**
1590
+ *
1591
+ * Like some methds in class `IO`, StringIO.each honors two special record separators;
1592
+ * see {Special Line Separators}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Special+Line+Separator+Values].
1593
+ *
1594
+ * ```
1595
+ * strio = StringIO.new(TEXT)
1596
+ * strio.each_line('') {|line| p line } # Read as paragraphs (separated by blank lines).
1597
+ * ```
1598
+ *
1599
+ * Output:
1600
+ *
1601
+ * ```
1602
+ * "First line\nSecond line\n\n"
1603
+ * "Fourth line\nFifth line\n"
1604
+ * ```
1605
+ *
1606
+ * ```
1607
+ * strio = StringIO.new(TEXT)
1608
+ * strio.each_line(nil) {|line| p line } # "Slurp"; read it all.
1609
+ * ```
1610
+ *
1611
+ * Output:
1612
+ *
1613
+ * ```
1614
+ * "First line\nSecond line\n\nFourth line\nFifth line\n"
1615
+ * ```
1616
+ *
1617
+ * **Keyword Argument `chomp`**
1618
+ *
1619
+ * With keyword argument `chomp` given as `true` (the default is `false`),
1620
+ * removes trailing newline (if any) from each line:
1621
+ *
1622
+ * ```
1623
+ * strio = StringIO.new(TEXT)
1624
+ * strio.each_line(chomp: true) {|line| p line }
1625
+ * ```
1626
+ *
1627
+ * Output:
1628
+ *
1629
+ * ```
1630
+ * "First line"
1631
+ * "Second line"
1632
+ * ""
1633
+ * "Fourth line"
1634
+ * "Fifth line"
1635
+ * ```
1636
+ *
1637
+ * With no block given, returns a new {Enumerator}[https://docs.ruby-lang.org/en/master/Enumerator.html].
1638
+ *
1639
+ * Related: StringIO.each_byte, StringIO.each_char, StringIO.each_codepoint.
1390
1640
  */
1391
1641
  static VALUE
1392
1642
  strio_each(int argc, VALUE *argv, VALUE self)
@@ -1587,10 +1837,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
1587
1837
  if (len < 0) {
1588
1838
  rb_raise(rb_eArgError, "negative length %ld given", len);
1589
1839
  }
1590
- if (len > 0 &&
1591
- (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
1840
+ if (eos_p(ptr)) {
1592
1841
  if (!NIL_P(str)) rb_str_resize(str, 0);
1593
- return Qnil;
1842
+ return len > 0 ? Qnil : rb_str_new(0, 0);
1594
1843
  }
1595
1844
  binary = 1;
1596
1845
  break;
@@ -1666,7 +1915,7 @@ strio_pread(int argc, VALUE *argv, VALUE self)
1666
1915
 
1667
1916
  struct StringIO *ptr = readable(self);
1668
1917
 
1669
- if (offset >= RSTRING_LEN(ptr->string)) {
1918
+ if (outside_p(ptr, offset)) {
1670
1919
  rb_eof_error();
1671
1920
  }
1672
1921
 
@@ -1797,12 +2046,20 @@ strio_truncate(VALUE self, VALUE len)
1797
2046
  }
1798
2047
 
1799
2048
  /*
1800
- * call-seq:
1801
- * strio.external_encoding => encoding
2049
+ * call-seq:
2050
+ * external_encoding -> encoding or nil
2051
+ *
2052
+ * Returns an Encoding object that represents the encoding of the string;
2053
+ * see {Encoding}[https://docs.ruby-lang.org/en/master/Encoding.html]:
2054
+ *
2055
+ * strio = StringIO.new('foo')
2056
+ * strio.external_encoding # => #<Encoding:UTF-8>
2057
+ *
2058
+ * Returns +nil+ if +self+ has no string and is in write mode:
2059
+ *
2060
+ * strio = StringIO.new(nil, 'w+')
2061
+ * strio.external_encoding # => nil
1802
2062
  *
1803
- * Returns the Encoding object that represents the encoding of the file.
1804
- * If the stream is write mode and no encoding is specified, returns
1805
- * +nil+.
1806
2063
  */
1807
2064
 
1808
2065
  static VALUE
@@ -1814,10 +2071,9 @@ strio_external_encoding(VALUE self)
1814
2071
 
1815
2072
  /*
1816
2073
  * call-seq:
1817
- * strio.internal_encoding => encoding
2074
+ * internal_encoding -> nil
1818
2075
  *
1819
- * Returns the Encoding of the internal string if conversion is
1820
- * specified. Otherwise returns +nil+.
2076
+ * Returns +nil+; for compatibility with IO.
1821
2077
  */
1822
2078
 
1823
2079
  static VALUE
@@ -1852,14 +2108,15 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
1852
2108
  enc = rb_find_encoding(ext_enc);
1853
2109
  if (!enc) {
1854
2110
  rb_io_enc_t convconfig;
1855
- int oflags, fmode;
2111
+ int oflags;
2112
+ rb_io_mode_t fmode;
1856
2113
  VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
1857
2114
  rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
1858
2115
  enc = convconfig.enc2;
1859
2116
  }
1860
2117
  }
1861
2118
  ptr->enc = enc;
1862
- if (!NIL_P(ptr->string) && WRITABLE(self)) {
2119
+ if (!NIL_P(ptr->string) && WRITABLE(self) && !str_chilled_p(ptr->string)) {
1863
2120
  rb_enc_associate(ptr->string, enc);
1864
2121
  }
1865
2122
 
@@ -1885,16 +2142,9 @@ strio_set_encoding_by_bom(VALUE self)
1885
2142
  }
1886
2143
 
1887
2144
  /*
1888
- * \IO streams for strings, with access similar to
1889
- * {IO}[rdoc-ref:IO];
1890
- * see {IO}[rdoc-ref:IO].
1891
- *
1892
- * === About the Examples
1893
- *
1894
- * Examples on this page assume that \StringIO has been required:
1895
- *
1896
- * require 'stringio'
2145
+ * :markup: markdown
1897
2146
  *
2147
+ * :include: stringio/stringio.md
1898
2148
  */
1899
2149
  void
1900
2150
  Init_stringio(void)
@@ -1902,7 +2152,7 @@ Init_stringio(void)
1902
2152
  #undef rb_intern
1903
2153
 
1904
2154
  #ifdef HAVE_RB_EXT_RACTOR_SAFE
1905
- rb_ext_ractor_safe(true);
2155
+ rb_ext_ractor_safe(true);
1906
2156
  #endif
1907
2157
 
1908
2158
  VALUE StringIO = rb_define_class("StringIO", rb_cObject);
@@ -1994,7 +2244,9 @@ Init_stringio(void)
1994
2244
  rb_define_method(StringIO, "set_encoding_by_bom", strio_set_encoding_by_bom, 0);
1995
2245
 
1996
2246
  {
2247
+ /* :stopdoc: */
1997
2248
  VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
2249
+ /* :startdoc: */
1998
2250
  rb_define_method(mReadable, "readchar", strio_readchar, 0);
1999
2251
  rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
2000
2252
  rb_define_method(mReadable, "readline", strio_readline, -1);
@@ -2004,7 +2256,9 @@ Init_stringio(void)
2004
2256
  rb_include_module(StringIO, mReadable);
2005
2257
  }
2006
2258
  {
2259
+ /* :stopdoc: */
2007
2260
  VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
2261
+ /* :startdoc: */
2008
2262
  rb_define_method(mWritable, "<<", strio_addstr, 1);
2009
2263
  rb_define_method(mWritable, "print", strio_print, -1);
2010
2264
  rb_define_method(mWritable, "printf", strio_printf, -1);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stringio
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.6
4
+ version: 3.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nobu Nakada
8
8
  - Charles Oliver Nutter
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-25 00:00:00.000000000 Z
11
+ date: 2025-11-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Pseudo `IO` class from/to `String`.
14
14
  email:
@@ -42,7 +42,7 @@ licenses:
42
42
  - Ruby
43
43
  - BSD-2-Clause
44
44
  metadata:
45
- changelog_uri: https://github.com/ruby/stringio/releases/tag/v3.1.6
45
+ changelog_uri: https://github.com/ruby/stringio/releases/tag/v3.1.8
46
46
  rdoc_options: []
47
47
  require_paths:
48
48
  - lib
@@ -57,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
57
  - !ruby/object:Gem::Version
58
58
  version: '0'
59
59
  requirements: []
60
- rubygems_version: 3.6.2
60
+ rubygems_version: 3.6.9
61
61
  specification_version: 4
62
62
  summary: Pseudo IO on String
63
63
  test_files: []