RUBY-240 Add StringIO methods to GridIO

This commit is contained in:
Kyle Banker 2011-03-29 15:27:13 -04:00
parent db1213fc5d
commit 002ddb06fc
2 changed files with 158 additions and 1 deletions

View File

@ -168,6 +168,91 @@ module Mongo
def tell
@file_position
end
alias :pos :tell
# Rewind the file. This is equivalent to seeking to the zeroth position.
#
# @return [Integer] the position of the file after rewinding (always zero).
def rewind
raise GridError, "file not opened for read" unless @mode[0] == "r"
seek(0)
end
# Return a boolean indicating whether the position pointer is
# at the end of the file.
#
# @return [Boolean]
def eof
raise GridError, "file not opened for read" unless @mode[0] == "r"
@file_position >= @file_length
end
alias :eof? :eof
# Return the next line from a GridFS file. This probably
# makes sense only if you're storing plain text. This method
# has a somewhat tricky API, which it inherits from Ruby's
# StringIO#gets.
#
# @param [String, Integer] separator or length. If a separator,
# read up to the separator. If a length, read the +length+ number
# of bytes. If nil, read the entire file.
# @param [Integer] length If a separator is provided, then
# read until either finding the separator or
# passing over the +length+ number of bytes.
#
# @return [String]
def gets(separator="\n", length=nil)
if separator.nil?
read_all
elsif separator.is_a?(Integer)
read_length(separator)
elsif separator.length > 1
result = ''
len = 0
match_idx = 0
match_num = separator.length - 1
to_match = separator[match_idx]
if length
matcher = lambda {|idx, num| idx < num && len < length }
else
matcher = lambda {|idx, num| idx < num}
end
while matcher.call(match_idx, match_num) && char = getc
result << char
len += 1
if char == to_match
while match_idx < match_num do
match_idx += 1
to_match = separator[match_idx]
char = getc
result << char
if char != to_match
match_idx = 0
to_match = separator[match_idx]
break
end
end
end
end
result
else
result = ''
len = 0
while char = getc
result << char
len += 1
break if char == separator || (length ? len >= length : false)
end
result
end
end
# Return the next byte from the GridFS file.
#
# @return [String]
def getc
read_length(1)
end
# Creates or updates the document from the files collection that
# stores the chunks' metadata. The file becomes available only after
@ -256,7 +341,7 @@ module Mongo
if length.nil?
to_read = remaining
else
to_read = length > remaining ? remaining : length
to_read = length > remaining ? remaining : length
end
return nil unless remaining > 0

View File

@ -32,6 +32,78 @@ class GridIOTest < Test::Unit::TestCase
end
end
context "StringIO methods" do
setup do
@filename = 'test'
@mode = 'w'
@data = "012345678\n" * 100000
@file = GridIO.new(@files, @chunks, @filename, @mode)
@file.write(@data)
@file.close
end
should "read data character by character using" do
bytes = 0
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
while char = file.getc
bytes += 1
end
assert_equal bytes, 1_000_000
end
should "read length is a length is given" do
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
string = file.gets(1000)
assert_equal string.length, 1000
bytes = 0
bytes += string.length
while string = file.gets(1000)
bytes += string.length
end
assert_equal bytes, 1_000_000
end
should "read to the end of the line by default and assign to $_" do
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
string = file.gets
assert_equal 10, string.length
end
should "read to a given separator" do
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
string = file.gets("5")
assert_equal 6, string.length
end
should "read a multi-character separator" do
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
string = file.gets("45")
assert_equal 6, string.length
string = file.gets("45")
assert_equal "678\n012345", string
string = file.gets("\n01")
assert_equal "678\n01", string
end
should "read a mult-character separator with a length" do
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
string = file.gets("45", 3)
assert_equal 3, string.length
end
should "tell position, eof, and rewind" do
file = GridIO.new(@files, @chunks, nil, "r", :query => {:_id => @file.files_id})
string = file.read(1000)
assert_equal 1000, file.pos
assert !file.eof?
file.read
assert file.eof?
file.rewind
assert_equal 0, file.pos
assert_equal 1_000_000, file.read.length
end
end
context "Seeking" do
setup do
@filename = 'test'