"Rework" the csv parsing to cook metatable for header access instead of whatever the fuck I was doing

This commit is contained in:
2025-11-15 18:06:21 +01:00
parent c145ad0900
commit 11f0bbee53
2 changed files with 85 additions and 4 deletions

View File

@@ -520,4 +520,57 @@ phoenix_brigade 30 0.1 shielding_basic battle_physicist_basic reinforced_battery
assert(rows2.Headers[1] == rows.Headers[1], "First header should match")
end)
-- Test metatable: row[1] and row.foobar return same value
test("metatable row[1] equals row.header", function()
local csv = "Id Name Value\n1 Test 100"
local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true })
if err then error("fromCSV error: " .. err) end
assert(rows[1][1] == rows[1].Id, "row[1] should equal row.Id")
assert(rows[1][2] == rows[1].Name, "row[2] should equal row.Name")
assert(rows[1][3] == rows[1].Value, "row[3] should equal row.Value")
assert(rows[1].Id == "1", "row.Id should be '1'")
assert(rows[1][1] == "1", "row[1] should be '1'")
end)
-- Test metatable: setting via header name updates numeric index
test("metatable set via header name", function()
local csv = "Id Name Value\n1 Test 100"
local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true })
if err then error("fromCSV error: " .. err) end
rows[1].Id = "999"
assert(rows[1][1] == "999", "Setting row.Id should update row[1]")
assert(rows[1].Id == "999", "row.Id should be '999'")
end)
-- Test metatable: error on unknown header assignment
test("metatable error on unknown header", function()
local csv = "Id Name Value\n1 Test 100"
local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true })
if err then error("fromCSV error: " .. err) end
local ok, errMsg = pcall(function()
rows[1].UnknownHeader = "test"
end)
assert(ok == false, "Should error on unknown header")
assert(string.find(errMsg, "unknown header"), "Error should mention unknown header")
end)
-- Test metatable: numeric indices still work
test("metatable numeric indices work", function()
local csv = "Id Name Value\n1 Test 100"
local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true })
if err then error("fromCSV error: " .. err) end
rows[1][1] = "999"
assert(rows[1].Id == "999", "Setting row[1] should update row.Id")
assert(rows[1][1] == "999", "row[1] should be '999'")
end)
-- Test metatable: numeric keys work normally
test("metatable numeric keys work", function()
local csv = "Id Name Value\n1 Test 100"
local rows, err = fromCSV(csv, { delimiter = "\t", hasheader = true })
if err then error("fromCSV error: " .. err) end
rows[1][100] = "hundred"
assert(rows[1][100] == "hundred", "Numeric keys should work")
end)
print("\nAll tests completed!")

View File

@@ -209,17 +209,45 @@ function fromCSV(csv, options)
if hasheader and #allRows > 0 then
local headers = allRows[1]
local headerMap = {}
for j = 1, #headers do
if headers[j] ~= nil and headers[j] ~= "" then
local headerName = trim(headers[j])
headerMap[headerName] = j
end
end
local header_mt = {
headers = headerMap,
__index = function(t, key)
local mt = getmetatable(t)
if type(key) == "string" and mt.headers and mt.headers[key] then
return rawget(t, mt.headers[key])
end
return rawget(t, key)
end,
__newindex = function(t, key, value)
local mt = getmetatable(t)
if type(key) == "string" and mt.headers then
if mt.headers[key] then
rawset(t, mt.headers[key], value)
else
error("unknown header: " .. tostring(key))
end
else
rawset(t, key, value)
end
end
}
local rows = {}
for ii = 2, #allRows do
local row = {}
local dataRow = allRows[ii]
for j = 1, #dataRow do
row[j] = dataRow[j]
if headers[j] ~= nil and headers[j] ~= "" then
local headerName = trim(headers[j])
row[headerName] = dataRow[j]
end
end
setmetatable(row, header_mt)
table.insert(rows, row)
end
rows.Headers = headers