submission.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. local io = io
  2. local csv = require "csv"
  3. local M = {} -- Submission module
  4. -- Adapted from lua-núcleo
  5. local function escape_pattern(s)
  6. local matches = {
  7. ["^"] = "%^";
  8. ["$"] = "%$";
  9. ["("] = "%(";
  10. [")"] = "%)";
  11. ["%"] = "%%";
  12. ["."] = "%.";
  13. ["["] = "%[";
  14. ["]"] = "%]";
  15. ["*"] = "%*";
  16. ["+"] = "%+";
  17. ["-"] = "%-";
  18. ["?"] = "%?";
  19. ["\0"] = "%z";
  20. }
  21. return (s:gsub(".", matches))
  22. end
  23. M.deposit = function(path)
  24. local sub_data = assert(csv.open(path))
  25. local md = {}
  26. local prev_ref, prev_k
  27. -- Collate metadata.
  28. local i = 1
  29. for row in sub_data:lines() do
  30. ref, k, v = table.unpack(row)
  31. -- nil-out empty cells (they come through as "")
  32. if ref == "" then ref = nil end
  33. if k == "" then k = nil end
  34. if v == "" then v = nil end
  35. print("Parsing row:", ref, k, v)
  36. -- v can be a legit false value.
  37. if ref and not k and v == nil then
  38. -- This can be a placeholder for ordering purposes.
  39. md[ref] = md_ref or {}
  40. goto continue
  41. elseif v == nil then
  42. goto continue
  43. else
  44. -- If ref or k are missing, reuse the previous one.
  45. if ref then prev_ref = ref
  46. else
  47. if not prev_ref then
  48. -- If column 1 is empty, it must have been set in a
  49. -- previous row.
  50. error(string.format(
  51. "Reference in column 1, row %d not found!", i), 2)
  52. end
  53. ref = prev_ref
  54. end
  55. if k then prev_k = k
  56. else
  57. if not prev_k then
  58. -- If column 2 is empty, it must have been set in a
  59. -- previous row.
  60. error(string.format(
  61. "Property key in column 2, row %d not found!", i), 2)
  62. end
  63. k = prev_k
  64. end
  65. end
  66. md[ref] = md[ref] or {path = ref, _sort = i}
  67. md[ref][k] = md[ref][k] or {}
  68. table.insert(md[ref][k], v)
  69. ::continue::
  70. i = i + 1
  71. end
  72. -- Move md to an ordered list.
  73. mdlist = {}
  74. for _, v in pairs(md) do table.insert(mdlist, v) end
  75. table.sort(mdlist, function (a, b) return (a._sort < b._sort) end)
  76. -- Infer structure from paths and row ordering.
  77. for i, v in ipairs(mdlist) do
  78. for j = i + 1, #mdlist do
  79. --print(string.format("comparing %s : %s", v.path, mdlist[j].path))
  80. if not v["next"] and
  81. mdlist[j].path:match("(.*/)") == v.path:match("(.*/)") then
  82. --print("next match.")
  83. v["next"] = mdlist[j].path
  84. end
  85. if not v.firstChild and
  86. mdlist[j].path:match("^" .. escape_pattern(v.path)) then
  87. --print("First child match.")
  88. v.firstChild = mdlist[j].path
  89. end
  90. end
  91. v._sort = nil
  92. end
  93. return mdlist
  94. end
  95. return M