csv.lua: now that a buffer looks like a string, reading strings is easier

This commit is contained in:
Geoff Leyland 2014-05-26 21:21:14 +12:00
parent 3d3bbfb6c1
commit be4420ae62

View File

@ -213,6 +213,13 @@ function file_buffer:sub(a, b)
end end
--- Close a file buffer
function file_buffer:close()
self.file:close()
self.file = nil
end
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
--- Iterate through the records in a file --- Iterate through the records in a file
@ -220,8 +227,7 @@ end
-- and line-endings might not be native, we read the file in chunks of -- and line-endings might not be native, we read the file in chunks of
-- we read the file in chunks using a file_buffer, rather than line-by-line -- we read the file in chunks using a file_buffer, rather than line-by-line
-- using io.lines. -- using io.lines.
local function separated_values_iterator(file, parameters) local function separated_values_iterator(buffer, parameters)
local buffer = file_buffer:new(file, parameters.buffer_size)
local filename = parameters.filename or "<unknown>" local filename = parameters.filename or "<unknown>"
local field_start = 1 local field_start = 1
local line_start = 1 local line_start = 1
@ -230,10 +236,16 @@ local function separated_values_iterator(file, parameters)
build_column_name_map(parameters.columns) build_column_name_map(parameters.columns)
local column_index_map local column_index_map
local advance
local function advance(n) if buffer.truncate then
field_start = field_start + n advance = function(n)
buffer:truncate(field_start) field_start = field_start + n
buffer:truncate(field_start)
end
else
advance = function(n)
field_start = field_start + n
end
end end
@ -356,29 +368,31 @@ end
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
local file_mt = local buffer_mt =
{ {
lines = function(t) lines = function(t)
return coroutine.wrap(function() return coroutine.wrap(function()
separated_values_iterator(t.file, t.parameters) separated_values_iterator(t.buffer, t.parameters)
end) end)
end, end,
close = function(t) close = function(t)
t.file:close() if t.buffer.close then t.buffer:close() end
end, end,
name = function(t) name = function(t)
return t.parameters.filename return t.parameters.filename
end, end,
} }
file_mt.__index = file_mt buffer_mt.__index = buffer_mt
local function use(file, parameters) local function use(buffer, parameters)
local f = { file = file, parameters = parameters } local f = { buffer = buffer, parameters = parameters }
return setmetatable(f, file_mt) return setmetatable(f, buffer_mt)
end end
------------------------------------------------------------------------------
--- Open a file for reading as a delimited file --- Open a file for reading as a delimited file
-- @return a file object -- @return a file object
local function open( local function open(
@ -390,31 +404,21 @@ local function open(
parameters = parameters or {} parameters = parameters or {}
parameters.filename = filename parameters.filename = filename
return use(file, parameters) return use(file_buffer:new(file), parameters)
end end
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
local stringfh_mt = local function makename(s)
{ local t = {}
read = function(self, bytes) t[#t+1] = "<(String) "
if not self._string then return nil end t[#t+1] = (s:gmatch("[^\n]+")() or ""):sub(1,15)
if #t[#t] > 14 then t[#t+1] = "..." end
t[#t+1] = " >"
return table.concat(t)
end
local read_rv
read_rv, self._string =
self._string:sub(1, bytes), self._string:sub(bytes+1)
if #self._string == 0 then
self._string = nil
end
return read_rv
end,
close = function()
end
}
stringfh_mt.__index = stringfh_mt
--- Open a string for reading as a delimited file --- Open a string for reading as a delimited file
-- @return a file object -- @return a file object
@ -425,21 +429,13 @@ local function openstring(
parameters = parameters or {} parameters = parameters or {}
local function makename()
local t = {}
t[#t+1] = "<(String) "
t[#t+1] = (filecontents:gmatch("[^\n]+")() or ""):sub(1,15)
if #t[#t] > 14 then t[#t+1] = "..." end
t[#t+1] = " >"
return table.concat(t)
end
parameters.filename = parameters.filename or makename() parameters.filename = parameters.filename or makename(s)
parameters.buffer_size = parameters.buffer_size or #filecontents parameters.buffer_size = parameters.buffer_size or #filecontents
local fileh = setmetatable({_string = filecontents}, stringfh_mt) return use(filecontents, parameters)
return use(fileh, parameters)
end end
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
return { open = open, openstring = openstring, use = use } return { open = open, openstring = openstring, use = use }