5 DEFAULT_RECORD_SEPARATOR = "\n" unless defined?(::DEFAULT_RECORD_SEPARATOR)
9 return io unless block_given?
18 attr_reader :string, :pos
21 def initialize(string = "", mode = Undefined)
22 @string = Type.coerce_to string, String, :to_str
26 unless mode == Undefined
27 if mode.is_a?(Integer)
28 mode_from_integer(mode)
30 mode = StringValue(mode)
31 mode_from_string(mode)
34 mode_from_string("r+")
40 def initialize_copy(from)
41 from = Type.coerce_to(from, StringIO, :to_strio)
43 self.taint if from.tainted?
45 @string = from.instance_variable_get(:@string).dup
46 @append = from.instance_variable_get(:@append)
47 @readable = from.instance_variable_get(:@readable)
48 @writable = from.instance_variable_get(:@writable)
50 @pos = from.instance_variable_get(:@pos)
51 @lineno = from.instance_variable_get(:@lineno)
66 raise IOError, "not opened for writing" unless @writable
70 return 0 if str.empty?
72 if @append || @pos == @string.length
75 elsif @pos > @string.size
76 @string[@string.size .. @pos] = "\000" * (@pos - @string.size)
80 @string[@pos, str.length] = str
82 @string.taint if str.tainted?
87 alias_method :syswrite, :write
90 raise IOError, "closed stream" if closed?
91 @readable = @writable = nil
95 !@readable && !@writable
99 raise IOError, "closing non-duplex IO for reading" unless @readable
108 raise IOError, "closing non-duplex IO for writing" unless @writable
117 raise IOError, "not opened for reading" unless @readable
118 if @pos < @string.length
119 @string[@pos..-1].each_byte { |b| @pos += 1; yield b}
125 raise IOError, "not opened for reading" unless @readable
126 sep = StringValue(sep) unless sep.nil?
127 while line = self.getline(sep)
132 alias_method :each_line, :each
137 alias_method :eof, :eof?
140 raise NotImplementedError, "StringIO#fcntl is not implemented"
156 raise IOError, "not opened for reading" unless @readable
158 @pos += 1 unless self.eof?
163 $_ = self.getline(sep)
169 alias_method :tty?, :isatty
174 alias_method :size, :length
185 raise Errno::EINVAL if pos < 0
190 raise IOError, "not opened for writing" unless @writable
191 args << $_ if args.empty?
192 args.map! { |x| x.nil? ? "nil" : x }
193 self.write((args << $\).flatten.join)
198 raise IOError, "not opened for writing" unless @writable
201 self.write(args.shift % args)
203 self.write(args.first)
210 raise IOError, "not opened for writing" unless @writable
215 char = Type.coerce_to obj, Integer, :to_int
218 if @append || @pos == @string.length
220 @pos = @string.length
221 elsif @pos > @string.length
222 @string[@string.length .. @pos] = "\000" * (@pos - @string.length)
224 @pos = @string.length
235 self.write(DEFAULT_RECORD_SEPARATOR)
240 elsif RecursionGuard.inspecting?(arg)
244 arg = Type.coerce_to(arg, Array, :to_ary)
245 RecursionGuard.inspect(arg) do
246 arg.each { |a| self.puts a }
255 self.write(DEFAULT_RECORD_SEPARATOR) if !line.empty? && line[-1] != ?\n
262 def read(length = Undefined, buffer = "")
263 raise IOError, "not opened for reading" unless @readable
264 return nil if self.eof?
266 buffer = StringValue(buffer)
268 if length == Undefined
269 buffer.replace(@string[@pos..-1])
272 length = Type.coerce_to length, Integer, :to_int
273 raise ArgumentError if length < 0
274 buffer.replace(@string[@pos, length])
275 @pos += buffer.length
282 raise IO::EOFError, "end of file reached" if self.eof?
286 def readline(sep = $/)
287 raise IO::EOFError, "end of file reached" if self.eof?
288 $_ = self.getline(sep)
291 def readlines(sep = $/)
292 raise IOError, "not opened for reading" unless @readable
294 while line = self.getline(sep)
300 def reopen(string = Undefined, mode = Undefined)
301 unless string == Undefined
302 if !string.is_a?(String) && mode == Undefined
303 string = Type.coerce_to(string, StringIO, :to_strio)
304 self.taint if string.tainted?
305 @string = string.string
307 @string = StringValue(string)
309 unless mode == Undefined
310 if mode.is_a?(Integer)
311 mode_from_integer(mode)
313 mode = StringValue(mode)
314 mode_from_string(mode)
317 mode_from_string("r+")
321 mode_from_string("r+")
335 def seek(to, whence = IO::SEEK_SET)
336 #raise IOError if self.closed?
337 to = Type.coerce_to to, Integer, :to_int
344 when IO::SEEK_SET, nil
346 raise Errno::EINVAL, "invalid whence"
349 raise Errno::EINVAL if to < 0
357 @string = StringValue(string)
370 def sysread(length = Undefined, buffer = "")
371 raise IO::EOFError, "end of file reached" if self.eof?
380 raise IOError, "not opened for writing" unless @writable
381 len = Type.coerce_to length, Integer, :to_int
382 raise Errno::EINVAL, "negative length" if len < 0
383 if len < @string.size
384 @string[len .. @string.size] = ""
386 @string << "\000" * (len - @string.size)
392 raise IOError, "not opened for reading" unless @readable
393 char = Type.coerce_to char, Integer, :to_int
395 if @pos > @string.size
396 @string[@string.size .. @pos] = "\000" * (@pos - @string.size)
414 def mode_from_string(mode)
415 @readable = @writable = @append = false
440 def mode_from_integer(mode)
441 @readable = @writable = @append = false
443 case mode & (IO::RDONLY | IO::WRONLY | IO::RDWR)
455 @append = true if (mode & IO::APPEND) != 0
456 @string.replace("") if (mode & IO::TRUNC) != 0
459 def getline(sep = $/)
460 raise IOError unless @readable
462 sep = StringValue(sep) unless sep.nil?
464 return nil if self.eof?
467 line = @string[@pos .. -1]
470 if stop = @string.index("\n\n", @pos)
472 line = @string[@pos .. stop - 2]
473 while @string[stop] == ?\n
478 line = @string[@pos .. -1]
482 if stop = @string.index(sep, @pos)
483 line = @string[@pos .. stop]
486 line = @string[@pos .. -1]