Add options.override, refactor

This commit is contained in:
Enrique García Cota 2022-05-21 01:24:44 +02:00
parent 78c67816ef
commit dc5a7f48d2
3 changed files with 134 additions and 137 deletions

View File

@ -13,7 +13,6 @@ local inspect = {Options = {}, }
inspect._VERSION = 'inspect.lua 3.1.0'
inspect._URL = 'http://github.com/kikito/inspect.lua'
inspect._DESCRIPTION = 'human-readable representations of tables'
@ -41,8 +40,6 @@ inspect._LICENSE = [[
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end })
inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end })
local tostring = tostring
local rep = string.rep
@ -50,6 +47,7 @@ local match = string.match
local char = string.char
local gsub = string.gsub
local fmt = string.format
local concat = table.concat
local function rawpairs(t)
return next, t, nil
@ -150,33 +148,8 @@ local function countCycles(x, cycles)
end
end
local function puts(buf, str)
buf.n = buf.n + 1
buf[buf.n] = str
end
local Inspector = {}
local Inspector_mt = { __index = Inspector }
local function tabify(inspector)
puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
end
function Inspector:getId(v)
local id = self.ids[v]
local ids = self.ids
local function getId(ids, v)
local id = ids[v]
if not id then
local tv = type(v)
id = (ids[tv] or 0) + 1
@ -185,61 +158,77 @@ function Inspector:getId(v)
return tostring(id)
end
function Inspector:putValue(v)
local buf = self.buf
local function puts(buf, str)
buf.n = buf.n + 1
buf[buf.n] = str
end
local function tabify(buf, level, options)
local newline = options and options.newline or "\n"
local indent = options and options.indent or " "
puts(buf, newline .. rep(indent, level))
end
local function putValue(v, buf, cycles, ids, level,
options)
if options and options.override then
local s = options.override(v)
if s ~= nil then
puts(buf, s)
return
end
end
local tv = type(v)
if tv == 'string' then
puts(buf, smartQuote(escape(v)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
tv == 'cdata' or tv == 'ctype' then
puts(buf, tostring(v))
elseif tv == 'table' and not self.ids[v] then
elseif tv == 'table' and not ids[v] then
local t = v
if t == inspect.KEY or t == inspect.METATABLE then
puts(buf, tostring(t))
elseif self.level >= self.depth then
local depth = options and options.depth
if depth and level >= depth then
puts(buf, '{...}')
else
if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end
if cycles[t] > 1 then puts(buf, fmt('<%d>', getId(ids, t))) end
local keys, keysLen, seqLen = getKeys(t)
local nextLevel = level + 1
puts(buf, '{')
self.level = self.level + 1
for i = 1, seqLen + keysLen do
if i > 1 then puts(buf, ',') end
if i <= seqLen then
puts(buf, ' ')
self:putValue(t[i])
putValue(t[i], buf, cycles, ids, nextLevel, options)
else
local k = keys[i - seqLen]
tabify(self)
tabify(buf, level + 1, options)
if isIdentifier(k) then
puts(buf, k)
else
puts(buf, "[")
self:putValue(k)
putValue(k, buf, cycles, ids, nextLevel, options)
puts(buf, "]")
end
puts(buf, ' = ')
self:putValue(t[k])
putValue(t[k], buf, cycles, ids, nextLevel, options)
end
end
local mt = getmetatable(t)
if type(mt) == 'table' then
if seqLen + keysLen > 0 then puts(buf, ',') end
tabify(self)
tabify(buf, level + 1, options)
puts(buf, '<metatable> = ')
self:putValue(mt)
putValue(mt, buf, cycles, ids, nextLevel, options)
end
self.level = self.level - 1
if keysLen > 0 or type(mt) == 'table' then
tabify(self)
tabify(buf, level, options)
elseif seqLen > 0 then
puts(buf, ' ')
end
@ -248,7 +237,7 @@ function Inspector:putValue(v)
end
else
puts(buf, fmt('<%s %d>', tv, self:getId(v)))
puts(buf, fmt('<%s %d>', tv, getId(ids, v)))
end
end
@ -256,28 +245,13 @@ end
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or (math.huge)
local newline = options.newline or '\n'
local indent = options.indent or ' '
local cycles = {}
countCycles(root, cycles)
local inspector = setmetatable({
buf = { n = 0 },
ids = {},
cycles = cycles,
depth = depth,
level = 0,
newline = newline,
indent = indent,
}, Inspector_mt)
local buf = { n = 0 }
putValue(root, buf, cycles, {}, 0, options)
inspector:putValue(root)
return table.concat(inspector.buf)
return concat(buf)
end
setmetatable(inspect, {

View File

@ -4,13 +4,12 @@ local record inspect
_URL: string
_DESCRIPTION: string
_LICENSE: string
KEY: table
METATABLE: table
record Options
depth: integer
newline: string
indent: string
override: function(any): string
end
end
@ -41,8 +40,6 @@ inspect._LICENSE = [[
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
inspect.KEY = setmetatable({}, {__tostring = function(): string return 'inspect.KEY' end})
inspect.METATABLE = setmetatable({}, {__tostring = function(): string return 'inspect.METATABLE' end})
local tostring = tostring
local rep = string.rep
@ -50,6 +47,7 @@ local match = string.match
local char = string.char
local gsub = string.gsub
local fmt = string.format
local concat = table.concat
local function rawpairs(t: table): function, table, nil
return next, t, nil
@ -135,7 +133,7 @@ local function getKeys(t: table): {any}, integer, integer
return keys, keysLen, seqLen
end
local function countCycles(x: any, cycles: {any:integer}): nil
local function countCycles(x: any, cycles: {table: integer}): nil
if x is table then
if cycles[x] then
cycles[x] = cycles[x] + 1
@ -150,33 +148,8 @@ local function countCycles(x: any, cycles: {any:integer}): nil
end
end
local function puts(buf: table, str:string): nil
buf.n = buf.n as integer + 1
buf[buf.n as integer] = str
end
-------------------------------------------------------------------
local type Inspector = record
buf: table
depth: integer
level: integer
ids: {any:integer}
newline: string
indent: string
cycles: {table: integer}
puts: function(string)
end
local Inspector_mt = {__index = Inspector}
local function tabify(inspector: Inspector)
puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
end
function Inspector:getId(v: any): string
local id: integer = self.ids[v]
local ids = self.ids
local function getId(ids: {any:integer}, v:any): string
local id: integer = ids[v]
if not id then
local tv: string = type(v)
id = (ids[tv] or 0) + 1
@ -185,61 +158,77 @@ function Inspector:getId(v: any): string
return tostring(id)
end
function Inspector:putValue(v: any)
local buf = self.buf
local function puts(buf: table, str:string): nil
buf.n = buf.n as integer + 1
buf[buf.n as integer] = str
end
local function tabify(buf: table, level: integer, options: inspect.Options)
local newline = options and options.newline or "\n"
local indent = options and options.indent or " "
puts(buf, newline .. rep(indent, level))
end
local function putValue(v: any, buf: table, cycles: {table: integer}, ids: {any: integer}, level: integer,
options: inspect.Options)
if options and options.override then
local s = options.override(v)
if s ~= nil then
puts(buf, s)
return
end
end
local tv: string = type(v)
if tv == 'string' then
puts(buf, smartQuote(escape(v as string)))
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
tv == 'cdata' or tv == 'ctype' then
puts(buf, tostring(v as number))
elseif tv == 'table' and not self.ids[v] then
elseif tv == 'table' and not ids[v] then
local t = v as table
if t == inspect.KEY or t == inspect.METATABLE then
puts(buf, tostring(t))
elseif self.level >= self.depth then
local depth = options and options.depth
if depth and level >= depth then
puts(buf, '{...}')
else
if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end
if cycles[t] > 1 then puts(buf, fmt('<%d>', getId(ids, t))) end
local keys, keysLen, seqLen = getKeys(t)
local nextLevel = level + 1
puts(buf, '{')
self.level = self.level + 1
for i = 1, seqLen + keysLen do
if i > 1 then puts(buf, ',') end
if i <= seqLen then
puts(buf, ' ')
self:putValue(t[i])
putValue(t[i], buf, cycles, ids, nextLevel, options)
else
local k = keys[i - seqLen]
tabify(self)
tabify(buf, level + 1, options)
if isIdentifier(k) then
puts(buf, k as string)
else
puts(buf, "[")
self:putValue(k)
putValue(k, buf, cycles, ids, nextLevel, options)
puts(buf, "]")
end
puts(buf, ' = ')
self:putValue(t[k])
putValue(t[k], buf, cycles, ids, nextLevel, options)
end
end
local mt = getmetatable(t)
if type(mt) == 'table' then
if seqLen + keysLen > 0 then puts(buf, ',') end
tabify(self)
tabify(buf, level + 1, options)
puts(buf, '<metatable> = ')
self:putValue(mt)
putValue(mt, buf, cycles, ids, nextLevel, options)
end
self.level = self.level - 1
if keysLen > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
tabify(self)
tabify(buf, level, options)
elseif seqLen > 0 then -- array tables have one extra space before closing }
puts(buf, ' ')
end
@ -248,7 +237,7 @@ function Inspector:putValue(v: any)
end
else
puts(buf, fmt('<%s %d>', tv, self:getId(v)))
puts(buf, fmt('<%s %d>', tv, getId(ids, v)))
end
end
@ -256,28 +245,13 @@ end
function inspect.inspect(root: any, options: inspect.Options): string
options = options or {}
local depth: integer = options.depth or (math.huge as integer)
local newline: string = options.newline or '\n'
local indent: string = options.indent or ' '
local cycles = {}
local cycles: {table: integer} = {}
countCycles(root, cycles)
local inspector = setmetatable({
buf = { n = 0 },
ids = {},
cycles = cycles,
depth = depth,
level = 0,
newline = newline,
indent = indent,
} as Inspector, Inspector_mt)
local buf: table = { n = 0 }
putValue(root, buf, cycles, {}, 0, options)
inspector:putValue(root)
return table.concat(inspector.buf as {string})
return concat(buf as {string})
end
setmetatable(inspect, {

View File

@ -262,6 +262,55 @@ describe( 'inspect', function()
end)
end)
describe('the override option', function()
it('changes how long strings are rendered, leaves values unaltered on nil', function()
local t = {short = "short", long = "a long string that should be shortened"}
assert.equal(unindent([[
{
long = "shortened",
short = "short"
}
]]), inspect(t, {override = function(x)
if type(x) == "string" and #x > 5 then
return '"shortened"'
end
end}))
end)
it('overrides hash values', function()
local t = { b = 2, c = "a" }
assert.equal(unindent([[
{
b = 2,
c = "changed"
}
]]), inspect(t, {override = function(x)
if x == "a" then
return '"changed"'
end
end}))
end)
it('can hide metatables', function()
local t = setmetatable({a = 1}, {__index = "a"})
assert.equal(unindent([[
{
a = 1,
<metatable> = {_}
}
]]), inspect(t, {override = function(x)
if type(x) == "table" and x.__index then
return "{_}"
end
end}))
end)
end)
describe('metatables', function()
it('includes the metatable as an extra hash attribute', function()