From fff87fea740b319ff91d2b4570e1b5264ffd86be Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Wed, 27 Feb 2013 22:31:18 +0100 Subject: [PATCH] Modified the sort function signature to also pass the original table, so not only keys are available when sorting, but also the values in the original table. --- README.md | 34 +++++++++++++++++++++++++++------- src/serpent.lua | 10 +++++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7fc94fb..c8b20b7 100644 --- a/README.md +++ b/README.md @@ -51,13 +51,13 @@ internal function, but set different options by default: * name (string) -- name; triggers full serialization with self-ref section * indent (string) -- indentation; triggers long multi-line output -* comment (true/False/maxlevel) -- provide stringified value in a comment (up to maxlevel of depth) -* sortkeys (true/False) -- sort keys -* sparse (true/False) -- force sparse encoding (no nil filling based on #t) -* compact (true/False) -- remove spaces -* fatal (true/False) -- raise fatal error on non-serilizable values -* nocode (true/False) -- disable bytecode serialization for easy comparison -* nohuge (true/False) -- disable checking numbers against undefined and huge values +* comment (true/false/maxlevel) -- provide stringified value in a comment (up to maxlevel of depth) +* sortkeys (true/false/function) -- sort keys +* sparse (true/false) -- force sparse encoding (no nil filling based on #t) +* compact (true/false) -- remove spaces +* fatal (true/false) -- raise fatal error on non-serilizable values +* nocode (true/false) -- disable bytecode serialization for easy comparison +* nohuge (true/false) -- disable checking numbers against undefined and huge values * maxlevel (number) -- specify max level up to which to expand nested tables * valignore (table) -- allows to specify a list of values to ignore (as keys) * keyallow (table) -- allows to specify the list of keys to be serialized. Any keys not in this list are not included in final output (as keys) @@ -72,6 +72,26 @@ line(a, {nocode = true, valignore = {[arrayToIgnore] = true}}) function todiff(a) return dump(a, {nocode = true, indent = ' '}) end ``` +## Sorting + +A custom sort function can be provided to sort the contents of tables. The function takes 2 parameters, the first being the table (a list) with the keys, the second the original table. It should modify the first table in-place, and return nothing. +For example, the following call will apply a sort function identical to the standard sort, except that it will not distinguish between lower- and uppercase. + +```lua +local mysort = function(k, o) -- k=keys, o=original table + local maxn, to = 12, {number = 'a', string = 'b'} + local function padnum(d) return ("%0"..maxn.."d"):format(d) end + local sort = function(a,b) + return ((k[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))):upper() + < ((k[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum))):upper() + end + table.sort(k, sort) +end + +local content = { some = 1, input = 2, to = 3, serialize = 4 } +local result = require('serpent').block(content, {sortkeys = mysort}) +``` + ## Formatters Serpent supports a way to provide a custom formatter that allows to fully diff --git a/src/serpent.lua b/src/serpent.lua index 4808a5a..b4245e7 100644 --- a/src/serpent.lua +++ b/src/serpent.lua @@ -29,12 +29,12 @@ local function s(t, opts) local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] local safe = plain and n or '['..safestr(n)..']' return (path or '')..(plain and path and '.' or '')..safe, safe end - local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(o, n) + local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} local function padnum(d) return ("%0"..maxn.."d"):format(d) end - table.sort(o, function(a,b) - return (o[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) - < (o[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end + table.sort(k, function(a,b) + return (k[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) + < (k[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end local function val2str(t, name, indent, insref, path, plainindex, level) local ttype, level = type(t), (level or 0) local spath, sname = safename(path, name) @@ -63,7 +63,7 @@ local function s(t, opts) local maxn, o, out = #t, {}, {} for key = 1, maxn do table.insert(o, key) end for key in pairs(t) do if not o[key] then table.insert(o, key) end end - if opts.sortkeys then alphanumsort(o, opts.sortkeys) end + if opts.sortkeys then alphanumsort(o, t, opts.sortkeys) end for n, key in ipairs(o) do local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing