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 @string[@pos..-1].each_byte { |b| yield b }
123 raise IOError, "not opened for reading" unless @readable
124 sep = StringValue(sep) unless sep.nil?
125 while line = self.getline(sep)
130 alias_method :each_line, :each
135 alias_method :eof, :eof?
138 raise NotImplementedError, "StringIO#fcntl is not implemented"
154 raise IOError, "not opened for reading" unless @readable
156 @pos += 1 unless self.eof?
161 $_ = self.getline(sep)
167 alias_method :tty?, :isatty
172 alias_method :size, :length
183 raise Errno::EINVAL if pos < 0
188 raise IOError, "not opened for writing" unless @writable
189 args << $_ if args.empty?
190 args.map! { |x| x.nil? ? "nil" : x }
191 self.write((args << $\).flatten.join)
196 raise IOError, "not opened for writing" unless @writable
199 self.write(args.shift % args)
201 self.write(args.first)
208 raise IOError, "not opened for writing" unless @writable
213 char = Type.coerce_to obj, Integer, :to_int
216 if @append || @pos == @string.length
218 @pos = @string.length
219 elsif @pos > @string.length
220 @string[@string.length .. @pos] = "\000" * (@pos - @string.length)
222 @pos = @string.length
233 self.write(DEFAULT_RECORD_SEPARATOR)
238 elsif RecursionGuard.inspecting?(arg)
242 arg = Type.coerce_to(arg, Array, :to_ary)
243 RecursionGuard.inspect(arg) do
244 arg.each { |a| self.puts a }
253 self.write(DEFAULT_RECORD_SEPARATOR) if !line.empty? && line[-1] != ?\n
260 def read(length = Undefined, buffer = "")
261 raise IOError, "not opened for reading" unless @readable
262 return nil if self.eof?
264 buffer = StringValue(buffer)
266 if length == Undefined
267 buffer.replace(@string[@pos..-1])
270 length = Type.coerce_to length, Integer, :to_int
271 raise ArgumentError if length < 0
272 buffer.replace(@string[@pos, length])
273 @pos += buffer.length
280 raise IO::EOFError, "end of file reached" if self.eof?
284 def readline(sep = $/)
285 raise IO::EOFError, "end of file reached" if self.eof?
286 $_ = self.getline(sep)
289 def readlines(sep = $/)
290 raise IOError, "not opened for reading" unless @readable
292 while line = self.getline(sep)
298 def reopen(string = Undefined, mode = Undefined)
299 unless string == Undefined
300 if !string.is_a?(String) && mode == Undefined
301 string = Type.coerce_to(string, StringIO, :to_strio)
302 self.taint if string.tainted?
303 @string = string.string
305 @string = StringValue(string)
307 unless mode == Undefined
308 if mode.is_a?(Integer)
309 mode_from_integer(mode)
311 mode = StringValue(mode)
312 mode_from_string(mode)
315 mode_from_string("r+")
319 mode_from_string("r+")
333 def seek(to, whence = IO::SEEK_SET)
334 #raise IOError if self.closed?
335 to = Type.coerce_to to, Integer, :to_int
342 when IO::SEEK_SET, nil
344 raise Errno::EINVAL, "invalid whence"
347 raise Errno::EINVAL if to < 0
355 @string = StringValue(string)
368 def sysread(length = Undefined, buffer = "")
369 raise IO::EOFError, "end of file reached" if self.eof?
378 raise IOError, "not opened for writing" unless @writable
379 len = Type.coerce_to length, Integer, :to_int
380 raise Errno::EINVAL, "negative length" if len < 0
381 if len < @string.size
382 @string[len .. @string.size] = ""
384 @string << "\000" * (len - @string.size)
390 raise IOError, "not opened for reading" unless @readable
391 char = Type.coerce_to char, Integer, :to_int
393 if @pos > @string.size
394 @string[@string.size .. @pos] = "\000" * (@pos - @string.size)
412 def mode_from_string(mode)
413 @readable = @writable = @append = false
438 def mode_from_integer(mode)
439 @readable = @writable = @append = false
441 case mode & (IO::RDONLY | IO::WRONLY | IO::RDWR)
453 @append = true if (mode & IO::APPEND) != 0
454 @string.replace("") if (mode & IO::TRUNC) != 0
457 def getline(sep = $/)
458 raise IOError unless @readable
460 sep = StringValue(sep) unless sep.nil?
462 return nil if self.eof?
465 line = @string[@pos .. -1]
468 if stop = @string.index("\n\n", @pos)
470 line = @string[@pos .. stop - 2]
471 while @string[stop] == ?\n
476 line = @string[@pos .. -1]
480 if stop = @string.index(sep, @pos)
481 line = @string[@pos .. stop]
484 line = @string[@pos .. -1]