rubysl-stringio 1.0.0

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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/rubysl/stringio.rb +2 -0
  9. data/lib/rubysl/stringio/stringio.rb +611 -0
  10. data/lib/rubysl/stringio/version.rb +5 -0
  11. data/lib/stringio.rb +1 -0
  12. data/rubysl-stringio.gemspec +24 -0
  13. data/spec/append_spec.rb +83 -0
  14. data/spec/binmode_spec.rb +8 -0
  15. data/spec/bytes_spec.rb +12 -0
  16. data/spec/chars_spec.rb +12 -0
  17. data/spec/close_read_spec.rb +30 -0
  18. data/spec/close_spec.rb +22 -0
  19. data/spec/close_write_spec.rb +30 -0
  20. data/spec/closed_read_spec.rb +11 -0
  21. data/spec/closed_spec.rb +15 -0
  22. data/spec/closed_write_spec.rb +11 -0
  23. data/spec/codepoints_spec.rb +11 -0
  24. data/spec/each_byte_spec.rb +10 -0
  25. data/spec/each_char_spec.rb +12 -0
  26. data/spec/each_codepoint_spec.rb +12 -0
  27. data/spec/each_line_spec.rb +14 -0
  28. data/spec/each_spec.rb +14 -0
  29. data/spec/eof_spec.rb +10 -0
  30. data/spec/external_encoding_spec.rb +12 -0
  31. data/spec/fcntl_spec.rb +7 -0
  32. data/spec/fileno_spec.rb +8 -0
  33. data/spec/fixtures/classes.rb +15 -0
  34. data/spec/flush_spec.rb +8 -0
  35. data/spec/fsync_spec.rb +8 -0
  36. data/spec/getbyte_spec.rb +25 -0
  37. data/spec/getc_spec.rb +31 -0
  38. data/spec/gets_spec.rb +245 -0
  39. data/spec/initialize_copy_spec.rb +95 -0
  40. data/spec/initialize_spec.rb +193 -0
  41. data/spec/internal_encoding_spec.rb +12 -0
  42. data/spec/isatty_spec.rb +6 -0
  43. data/spec/length_spec.rb +6 -0
  44. data/spec/lineno_spec.rb +29 -0
  45. data/spec/lines_spec.rb +16 -0
  46. data/spec/open_spec.rb +215 -0
  47. data/spec/path_spec.rb +15 -0
  48. data/spec/pid_spec.rb +7 -0
  49. data/spec/pos_spec.rb +27 -0
  50. data/spec/print_spec.rb +113 -0
  51. data/spec/printf_spec.rb +60 -0
  52. data/spec/putc_spec.rb +105 -0
  53. data/spec/puts_spec.rb +173 -0
  54. data/spec/read_nonblock_spec.rb +29 -0
  55. data/spec/read_spec.rb +62 -0
  56. data/spec/readbyte_spec.rb +21 -0
  57. data/spec/readchar_spec.rb +19 -0
  58. data/spec/readline_spec.rb +127 -0
  59. data/spec/readlines_spec.rb +124 -0
  60. data/spec/readpartial_spec.rb +29 -0
  61. data/spec/reopen_spec.rb +303 -0
  62. data/spec/rewind_spec.rb +23 -0
  63. data/spec/seek_spec.rb +75 -0
  64. data/spec/set_encoding_spec.rb +34 -0
  65. data/spec/shared/codepoints.rb +45 -0
  66. data/spec/shared/each.rb +162 -0
  67. data/spec/shared/each_byte.rb +60 -0
  68. data/spec/shared/each_char.rb +50 -0
  69. data/spec/shared/eof.rb +24 -0
  70. data/spec/shared/getc.rb +43 -0
  71. data/spec/shared/isatty.rb +5 -0
  72. data/spec/shared/length.rb +12 -0
  73. data/spec/shared/read.rb +186 -0
  74. data/spec/shared/readchar.rb +29 -0
  75. data/spec/shared/sysread.rb +27 -0
  76. data/spec/shared/tell.rb +12 -0
  77. data/spec/shared/write.rb +134 -0
  78. data/spec/size_spec.rb +6 -0
  79. data/spec/string_spec.rb +49 -0
  80. data/spec/stringio_spec.rb +8 -0
  81. data/spec/sync_spec.rb +18 -0
  82. data/spec/sysread_spec.rb +27 -0
  83. data/spec/syswrite_spec.rb +18 -0
  84. data/spec/tell_spec.rb +6 -0
  85. data/spec/truncate_spec.rb +69 -0
  86. data/spec/tty_spec.rb +6 -0
  87. data/spec/ungetbyte_spec.rb +88 -0
  88. data/spec/ungetc_spec.rb +98 -0
  89. data/spec/write_nonblock_spec.rb +20 -0
  90. data/spec/write_spec.rb +18 -0
  91. metadata +267 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0e9dcf590f3bb0ca5bf669afb14bca85d488e1a
4
+ data.tar.gz: 7551574d3cb4596b9b8d8d2ae5f3ba0ff7f60d4e
5
+ SHA512:
6
+ metadata.gz: 06114a3723e28167f2ddca63309a9dccf8ccf6158be35a3ac4d8171e2ad5d86ef141d930427a24ddf782fb211e65f4df78c6442e15057f778be3b6ec6e038f88
7
+ data.tar.gz: 164566be1c5e2a2f94f44ee79b32f57f594bf5712d6845632f9468f76695baf3f1a19bedb77ea0a59669bb1f3fbfa2203b918cb8252662539624be8743c44fd2
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ env:
3
+ - RUBYLIB=lib
4
+ script: bundle exec mspec
5
+ rvm:
6
+ - 1.8.7
7
+ - rbx-nightly-18mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubysl-stringio.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubysl::Stringio
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubysl-stringio'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubysl-stringio
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ require "rubysl/stringio/version"
2
+ require "rubysl/stringio/stringio"
@@ -0,0 +1,611 @@
1
+ class StringIO
2
+
3
+ include Enumerable
4
+
5
+ DEFAULT_RECORD_SEPARATOR = "\n" unless defined?(::DEFAULT_RECORD_SEPARATOR)
6
+
7
+ # This is why we need undefined in Ruby
8
+ Undefined = Object.new
9
+
10
+ class Data
11
+ attr_accessor :string, :pos, :lineno
12
+
13
+ def initialize(string)
14
+ @string = string
15
+ @pos = @lineno = 0
16
+ end
17
+ end
18
+
19
+ def self.open(*args)
20
+ io = new(*args)
21
+ return io unless block_given?
22
+
23
+ begin
24
+ yield io
25
+ ensure
26
+ io.close
27
+ io.__data__.string = nil
28
+ self
29
+ end
30
+ end
31
+
32
+ attr_reader :__data__
33
+
34
+ def initialize(string="", mode=nil)
35
+ string = Rubinius::Type.coerce_to string, String, :to_str
36
+ @__data__ = Data.new string
37
+
38
+ if mode
39
+ if mode.is_a?(Integer)
40
+ mode_from_integer(mode)
41
+ else
42
+ mode = StringValue(mode)
43
+ mode_from_string(mode)
44
+ end
45
+ else
46
+ mode_from_string(string.frozen? ? "r" : "r+")
47
+ end
48
+
49
+ self
50
+ end
51
+
52
+ def initialize_copy(from)
53
+ from = Rubinius::Type.coerce_to(from, StringIO, :to_strio)
54
+
55
+ taint if from.tainted?
56
+
57
+ @append = from.instance_variable_get(:@append)
58
+ @readable = from.instance_variable_get(:@readable)
59
+ @writable = from.instance_variable_get(:@writable)
60
+ @__data__ = from.instance_variable_get(:@__data__)
61
+
62
+ self
63
+ end
64
+
65
+ def check_readable
66
+ raise IOError, "not opened for reading" unless @readable
67
+ end
68
+
69
+ private :check_readable
70
+
71
+ def check_writable
72
+ raise IOError, "not opened for writing" unless @writable
73
+ raise IOError, "unable to modify data" if @__data__.string.frozen?
74
+ end
75
+
76
+ private :check_writable
77
+
78
+ def each_byte
79
+ return to_enum :each_byte unless block_given?
80
+ check_readable
81
+
82
+ d = @__data__
83
+ string = d.string
84
+
85
+ while d.pos < string.length
86
+ byte = string.getbyte d.pos
87
+ d.pos += 1
88
+ yield byte
89
+ end
90
+
91
+ self
92
+ end
93
+
94
+ alias_method :bytes, :each_byte
95
+
96
+ def each_char
97
+ return to_enum :each_char unless block_given?
98
+ if $KCODE == "UTF8"
99
+ lookup = 7.downto(4)
100
+ while c = read(1) do
101
+ n = c[0]
102
+ leftmost_zero_bit = lookup.find{|i| n[i].zero? }
103
+ case leftmost_zero_bit
104
+ when 7 # ASCII
105
+ yield c
106
+ when 6 # UTF 8 complementary characters
107
+ next # Encoding error, ignore
108
+ else
109
+ more = read(6-leftmost_zero_bit)
110
+ break unless more
111
+ yield c+more
112
+ end
113
+ end
114
+ else
115
+ while s = read(1)
116
+ yield s
117
+ end
118
+ end
119
+
120
+ self
121
+ end
122
+
123
+ alias_method :chars, :each_char
124
+
125
+ def each(sep = $/)
126
+ return to_enum :each, sep unless block_given?
127
+ check_readable
128
+
129
+ while line = getline(sep)
130
+ yield line
131
+ end
132
+
133
+ self
134
+ end
135
+
136
+ alias_method :each_line, :each
137
+ alias_method :lines, :each
138
+
139
+ def <<(str)
140
+ write(str)
141
+ self
142
+ end
143
+
144
+ def binmode
145
+ self
146
+ end
147
+
148
+ def write(str)
149
+ check_writable
150
+
151
+ str = String(str)
152
+
153
+ return 0 if str.empty?
154
+
155
+ d = @__data__
156
+ pos = d.pos
157
+ string = d.string
158
+
159
+ if @append || pos == string.length
160
+ string << str
161
+ d.pos = string.length
162
+ elsif pos > string.bytesize
163
+ string[string.bytesize..pos] = "\000" * (pos - string.bytesize)
164
+ string << str
165
+ d.pos = string.bytesize
166
+ else
167
+ string[pos, str.length] = str
168
+ d.pos += str.length
169
+ string.taint if str.tainted?
170
+ end
171
+
172
+ return str.length
173
+ end
174
+ alias_method :syswrite, :write
175
+
176
+ def close
177
+ raise IOError, "closed stream" if closed?
178
+ @readable = @writable = nil
179
+ end
180
+
181
+ def closed?
182
+ !@readable && !@writable
183
+ end
184
+
185
+ def close_read
186
+ check_readable
187
+ @readable = nil
188
+ end
189
+
190
+ def closed_read?
191
+ !@readable
192
+ end
193
+
194
+ def close_write
195
+ check_writable
196
+ @writable = nil
197
+ end
198
+
199
+ def closed_write?
200
+ !@writable
201
+ end
202
+
203
+ def eof?
204
+ d = @__data__
205
+ d.pos >= d.string.bytesize
206
+ end
207
+ alias_method :eof, :eof?
208
+
209
+ def fcntl
210
+ raise NotImplementedError, "StringIO#fcntl is not implemented"
211
+ end
212
+
213
+ def fileno
214
+ nil
215
+ end
216
+
217
+ def flush
218
+ self
219
+ end
220
+
221
+ def fsync
222
+ 0
223
+ end
224
+
225
+ def getc
226
+ check_readable
227
+ d = @__data__
228
+
229
+ char = d.string[d.pos]
230
+ d.pos += 1 unless eof?
231
+ char
232
+ end
233
+
234
+ def getbyte
235
+ check_readable
236
+ d = @__data__
237
+
238
+ return nil if eof?
239
+
240
+ byte = d.string.getbyte(d.pos)
241
+ d.pos += 1
242
+ byte
243
+ end
244
+
245
+ def gets(sep = $/)
246
+ check_readable
247
+
248
+ $_ = getline(sep)
249
+ end
250
+
251
+ def isatty
252
+ false
253
+ end
254
+ alias_method :tty?, :isatty
255
+
256
+ def length
257
+ @string.length
258
+ end
259
+ alias_method :size, :length
260
+
261
+ def lineno
262
+ @__data__.lineno
263
+ end
264
+
265
+ def lineno=(line)
266
+ @__data__.lineno = line
267
+ end
268
+
269
+ def path
270
+ nil
271
+ end
272
+
273
+ def pid
274
+ nil
275
+ end
276
+
277
+ def pos
278
+ @__data__.pos
279
+ end
280
+
281
+ def pos=(pos)
282
+ raise Errno::EINVAL if pos < 0
283
+ @__data__.pos = pos
284
+ end
285
+
286
+ def print(*args)
287
+ check_writable
288
+ args << $_ if args.empty?
289
+ args.map! { |x| x.nil? ? "nil" : x }
290
+ write((args << $\).flatten.join)
291
+ nil
292
+ end
293
+
294
+ def printf(*args)
295
+ check_writable
296
+
297
+ if args.size > 1
298
+ write(args.shift % args)
299
+ else
300
+ write(args.first)
301
+ end
302
+
303
+ nil
304
+ end
305
+
306
+ def putc(obj)
307
+ check_writable
308
+
309
+ if obj.is_a?(String)
310
+ char = obj[0]
311
+ else
312
+ char = Rubinius::Type.coerce_to obj, Integer, :to_int
313
+ end
314
+
315
+ d = @__data__
316
+ pos = d.pos
317
+ string = d.string
318
+
319
+ if @append || pos == string.length
320
+ string << char
321
+ d.pos = string.length
322
+ elsif pos > string.length
323
+ string[string.length..pos] = "\000" * (pos - string.length)
324
+ string << char
325
+ d.pos = string.length
326
+ else
327
+ string[pos] = char
328
+ d.pos += 1
329
+ end
330
+
331
+ obj
332
+ end
333
+
334
+ def puts(*args)
335
+ if args.empty?
336
+ write(DEFAULT_RECORD_SEPARATOR)
337
+ else
338
+ args.each do |arg|
339
+ if arg.nil?
340
+ line = "nil"
341
+ elsif Thread.guarding? arg
342
+ line = "[...]"
343
+ else
344
+ begin
345
+ arg = Rubinius::Type.coerce_to(arg, Array, :to_ary)
346
+ Thread.recursion_guard arg do
347
+ arg.each { |a| puts a }
348
+ end
349
+ next
350
+ rescue
351
+ line = arg.to_s
352
+ end
353
+ end
354
+
355
+ write(line)
356
+ write(DEFAULT_RECORD_SEPARATOR) unless line[-1] == ?\n
357
+ end
358
+ end
359
+
360
+ nil
361
+ end
362
+
363
+ def read(length = nil, buffer = "")
364
+ check_readable
365
+ d = @__data__
366
+ pos = d.pos
367
+ string = d.string
368
+
369
+ buffer = StringValue(buffer)
370
+
371
+ if length
372
+ return nil if eof?
373
+ length = Rubinius::Type.coerce_to length, Integer, :to_int
374
+ raise ArgumentError if length < 0
375
+ buffer.replace(string[pos, length])
376
+ d.pos += buffer.length
377
+ else
378
+ return "" if eof?
379
+ buffer.replace(string[pos..-1])
380
+ d.pos = string.size
381
+ end
382
+
383
+ return buffer
384
+ end
385
+
386
+ def readchar
387
+ raise IO::EOFError, "end of file reached" if eof?
388
+ getc
389
+ end
390
+
391
+ alias_method :readbyte, :readchar
392
+
393
+ def readline(sep=$/)
394
+ raise IO::EOFError, "end of file reached" if eof?
395
+ check_readable
396
+
397
+ $_ = getline(sep)
398
+ end
399
+
400
+ def readlines(sep=$/)
401
+ check_readable
402
+
403
+ ary = []
404
+ while line = getline(sep)
405
+ ary << line
406
+ end
407
+
408
+ ary
409
+ end
410
+
411
+ def reopen(string=nil, mode=Undefined)
412
+ if string and not string.kind_of? String and mode.equal? Undefined
413
+ stringio = Rubinius::Type.coerce_to(string, StringIO, :to_strio)
414
+
415
+ taint if stringio.tainted?
416
+ initialize_copy stringio
417
+ else
418
+ mode = nil if mode.equal? Undefined
419
+ string = "" unless string
420
+
421
+ initialize string, mode
422
+ end
423
+
424
+ self
425
+ end
426
+
427
+ def rewind
428
+ d = @__data__
429
+ d.pos = d.lineno = 0
430
+ end
431
+
432
+ def seek(to, whence = IO::SEEK_SET)
433
+ raise IOError, "closed stream" if self.closed?
434
+ to = Rubinius::Type.coerce_to to, Integer, :to_int
435
+
436
+ case whence
437
+ when IO::SEEK_CUR
438
+ to += @__data__.pos
439
+ when IO::SEEK_END
440
+ to += @__data__.string.size
441
+ when IO::SEEK_SET, nil
442
+ else
443
+ raise Errno::EINVAL, "invalid whence"
444
+ end
445
+
446
+ raise Errno::EINVAL if to < 0
447
+
448
+ @__data__.pos = to
449
+
450
+ return 0
451
+ end
452
+
453
+ def size
454
+ @__data__.string.bytesize
455
+ end
456
+ alias_method :length, :size
457
+
458
+ def string
459
+ @__data__.string
460
+ end
461
+
462
+ def string=(string)
463
+ d = @__data__
464
+ d.string = StringValue(string)
465
+ d.pos = 0
466
+ d.lineno = 0
467
+ end
468
+
469
+ def sync
470
+ true
471
+ end
472
+
473
+ def sync=(val)
474
+ val
475
+ end
476
+
477
+ def sysread(length=nil, buffer="")
478
+ str = read(length, buffer)
479
+ raise IO::EOFError, "end of file reached" if str.nil?
480
+ str
481
+ end
482
+
483
+ def tell
484
+ @__data__.pos
485
+ end
486
+
487
+ def truncate(length)
488
+ check_writable
489
+ len = Rubinius::Type.coerce_to length, Integer, :to_int
490
+ raise Errno::EINVAL, "negative length" if len < 0
491
+ string = @__data__.string
492
+
493
+ if len < string.size
494
+ string[len..string.size] = ""
495
+ else
496
+ string << "\000" * (len - string.size)
497
+ end
498
+ return length
499
+ end
500
+
501
+ def ungetc(char)
502
+ check_readable
503
+
504
+ d = @__data__
505
+ pos = d.pos
506
+ string = d.string
507
+
508
+ char = Rubinius::Type.coerce_to char, Integer, :to_int
509
+
510
+ if pos > string.bytesize
511
+ string[string.bytesize..pos] = "\000" * (pos - string.bytesize)
512
+ d.pos -= 1
513
+ string[d.pos] = char
514
+ elsif pos > 0
515
+ d.pos -= 1
516
+ string[d.pos] = char
517
+ end
518
+
519
+ nil
520
+ end
521
+
522
+ def to_yaml_properties
523
+ []
524
+ end
525
+
526
+ def yaml_initialize(type, val)
527
+ @__data__ = Data.new("")
528
+ end
529
+
530
+ protected
531
+
532
+ def mode_from_string(mode)
533
+ @append = truncate = false
534
+
535
+ if mode[0] == ?r
536
+ @readable = true
537
+ @writable = mode[-1] == ?+ ? true : false
538
+ end
539
+
540
+ if mode[0] == ?w
541
+ @writable = truncate = true
542
+ @readable = mode[-1] == ?+ ? true : false
543
+ end
544
+
545
+ if mode[0] == ?a
546
+ @append = @writable = true
547
+ @readable = mode[-1] == ?+ ? true : false
548
+ end
549
+
550
+ d = @__data__
551
+ raise Errno::EACCES, "Permission denied" if @writable && d.string.frozen?
552
+ d.string.replace("") if truncate
553
+ end
554
+
555
+ def mode_from_integer(mode)
556
+ @readable = @writable = @append = false
557
+ d = @__data__
558
+
559
+ if mode == 0 or mode & IO::RDWR != 0
560
+ @readable = true
561
+ end
562
+
563
+ if mode & (IO::WRONLY | IO::RDWR) != 0
564
+ raise Errno::EACCES, "Permission denied" if d.string.frozen?
565
+ @writable = true
566
+ end
567
+
568
+ @append = true if (mode & IO::APPEND) != 0
569
+ d.string.replace("") if (mode & IO::TRUNC) != 0
570
+ end
571
+
572
+ def getline(sep = $/)
573
+ sep = StringValue(sep) unless sep.nil?
574
+
575
+ return nil if eof?
576
+
577
+ d = @__data__
578
+ pos = d.pos
579
+ string = d.string
580
+
581
+ if sep.nil?
582
+ line = string[pos..-1]
583
+ d.pos = string.size
584
+ elsif sep.empty?
585
+ if stop = string.index("\n\n", pos)
586
+ stop += 2
587
+ line = string[pos...stop]
588
+ while string[stop] == ?\n
589
+ stop += 1
590
+ end
591
+ d.pos = stop
592
+ else
593
+ line = string[pos..-1]
594
+ d.pos = string.size
595
+ end
596
+ else
597
+ if stop = string.index(sep, pos)
598
+ stop += sep.length
599
+ line = string[pos...stop]
600
+ d.pos = stop
601
+ else
602
+ line = string[pos..-1]
603
+ d.pos = string.size
604
+ end
605
+ end
606
+
607
+ d.lineno += 1
608
+
609
+ return line
610
+ end
611
+ end