From 679a5a3bcae1eb55aa4203132a3b1003c1e2c7b3 Mon Sep 17 00:00:00 2001 From: Paul Kulchenko Date: Fri, 1 Sep 2017 11:23:47 -0700 Subject: [PATCH] Added `metatostring` option to disable `__tostring` processing during serialization. Ref pkulchenko/MobDebug#27, pkulchenko/MobDebug#29. --- README.md | 2 ++ src/serpent.lua | 8 ++++---- t/test.lua | 5 +++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 890265b..a6e5bbe 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,8 @@ Similar to `pcall` and `loadstring` calls, `load` returns status as the first va * maxlevel (number) -- specify max level up to which to expand nested tables. * maxnum (number) -- specify max number of elements in a table. * maxlength (number) -- specify max length for all table elements. +* metatostring (True/false) -- use `__tostring` metamethod when serializing tables (**v0.29**); +set to `false` to disable and serialize the table as is, even when `__tostring` is present. * numformat (string; "%.17g") -- specify format for numeric values (shortest possible round-trippable double). * 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. diff --git a/src/serpent.lua b/src/serpent.lua index c5e862b..a5012c4 100644 --- a/src/serpent.lua +++ b/src/serpent.lua @@ -1,4 +1,4 @@ -local n, v = "serpent", 0.289 -- (C) 2012-17 Paul Kulchenko; MIT License +local n, v = "serpent", "0.29" -- (C) 2012-17 Paul Kulchenko; MIT License local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} local badtype = {thread = true, userdata = true, cdata = true} @@ -15,7 +15,7 @@ local function s(t, opts) local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) - local maxlen = tonumber(opts.maxlength) + local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge) local numformat = opts.numformat or "%.17g" local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0 @@ -53,9 +53,9 @@ local function s(t, opts) if type(mt) == 'table' then local to, tr = pcall(function() return mt.__tostring(t) end) local so, sr = pcall(function() return mt.__serialize(t) end) - if (to or so) then -- knows how to serialize itself + if (opts.metatostring ~= false and to or so) then -- knows how to serialize itself seen[t] = insref or spath - if so then t = sr else t = tostring(t) end + t = so and sr or tr ttype = type(t) end -- new value falls through to be serialized end diff --git a/t/test.lua b/t/test.lua index 532515e..5ba35a3 100644 --- a/t/test.lua +++ b/t/test.lua @@ -143,6 +143,11 @@ do assert(_a.y == 12, "metatable with __tostring and __index 1: failed") assert(_a[1] == 'a', "metatable with __tostring and __index 2: failed") assert(_a.x == 1, "metatable with __tostring and __index 3: failed") + + -- check that __tostring is not used when disabled + local _a = assert(loadstring(serpent.dump(a, {sparse = false, nocode = true, metatostring = false})))() + assert(_a[1] == 'a', "metatable with disabled __tostring and __index 1: failed") + assert(_a[2] == 'b', "metatable with disabled __tostring and __index 2: failed") end -- test circular reference in self-reference section