 
 This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.
| Performing Random Access on "Read-Once" Input Streams | ||
|---|---|---|
| Code | Expected | Actual | 
| require 'socket'
require 'stringio'
sock = TCPSocket.open("www.example.com", 80)
sock.write("GET /\n")
file = StringIO.new(sock.read)
file.read(10) | "<HTML>\r\n<H" | "<HTML>\r\n<H" | 
| file.rewind file.read(10) | "<HTML>\r\n<H" | "<HTML>\r\n<H" | 
| file.pos = 90 file.read(15) | " this web page " | " this web page " | 
| class BufferedIO 
  def initialize(io)
    @buff = StringIO.new
    @source = io
    @pos = 0
  end
  def read(x=nil)
    to_read = x ? to_read = x+@buff.pos-@buff.size : nil
    _append(@source.read(to_read)) if !to_read or to_read > 0
    @buff.read(x)
  end
  def pos=(x)
    read(x-@buff.pos) if x > @buff.size 
    @buff.pos = x
  end
  def seek(x, whence=IO::SEEK_SET)
    case whence
      when IO::SEEK_SET then self.pos=(x)     
      when IO::SEEK_CUR then self.pos=(@buff.pos+x)
     when IO::SEEK_END then read; self.pos=(@buff.size-x) # Note: this reads all the socket data.
    end
    pos
  end
  # Some methods can simply be delegated to the buffer.
  ["pos", "rewind", "tell"].each do |m|
    module_eval "def #{m}\n@buff.#{m}\nend"
  end
  private
  def _append(s)
  @buff << s
    @buff.pos -= s.size
  end
end
sock = TCPSocket.open("www.example.com", 80)
sock.write("GET /\n")
file = BufferedIO.new(sock)
file.read(10) | "<HTML>\r\n<H" | "<HTML>\r\n<H" | 
| file.rewind | 0 | 0 | 
| file.read(10) | "<HTML>\r\n<H" | "<HTML>\r\n<H" | 
| file.pos = 90 | 90 | 90 | 
| file.read(15) | " this web page " | " this web page " | 
| file.seek(-10, IO::SEEK_CUR) | 95 | 95 | 
| file.read(10) | " web page " | " web page " | 
| class BufferedIO
  def readline
    oldpos = @buff.pos    
    line = @buff.readline unless @buff.eof?
    if !line or line[-1] != ?\n
      _append(@source.readline) # Finish the line
      @buff.pos = oldpos        # Go back to where we were
      line = @buff.readline     # Read the line again
    end
    line
  end
end
file.readline | "by typing "example.com",\r\n" | "by typing "example.com",\r\n" |