mirror of
https://github.com/kikito/inspect.lua.git
synced 2024-12-15 14:34:21 +00:00
Add options.override, refactor
This commit is contained in:
parent
78c67816ef
commit
dc5a7f48d2
108
inspect.lua
108
inspect.lua
@ -13,7 +13,6 @@ local inspect = {Options = {}, }
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inspect._VERSION = 'inspect.lua 3.1.0'
|
inspect._VERSION = 'inspect.lua 3.1.0'
|
||||||
inspect._URL = 'http://github.com/kikito/inspect.lua'
|
inspect._URL = 'http://github.com/kikito/inspect.lua'
|
||||||
inspect._DESCRIPTION = 'human-readable representations of tables'
|
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
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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 tostring = tostring
|
||||||
local rep = string.rep
|
local rep = string.rep
|
||||||
@ -50,6 +47,7 @@ local match = string.match
|
|||||||
local char = string.char
|
local char = string.char
|
||||||
local gsub = string.gsub
|
local gsub = string.gsub
|
||||||
local fmt = string.format
|
local fmt = string.format
|
||||||
|
local concat = table.concat
|
||||||
|
|
||||||
local function rawpairs(t)
|
local function rawpairs(t)
|
||||||
return next, t, nil
|
return next, t, nil
|
||||||
@ -150,33 +148,8 @@ local function countCycles(x, cycles)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function puts(buf, str)
|
local function getId(ids, v)
|
||||||
buf.n = buf.n + 1
|
local id = ids[v]
|
||||||
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
|
|
||||||
if not id then
|
if not id then
|
||||||
local tv = type(v)
|
local tv = type(v)
|
||||||
id = (ids[tv] or 0) + 1
|
id = (ids[tv] or 0) + 1
|
||||||
@ -185,61 +158,77 @@ function Inspector:getId(v)
|
|||||||
return tostring(id)
|
return tostring(id)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Inspector:putValue(v)
|
local function puts(buf, str)
|
||||||
local buf = self.buf
|
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)
|
local tv = type(v)
|
||||||
if tv == 'string' then
|
if tv == 'string' then
|
||||||
puts(buf, smartQuote(escape(v)))
|
puts(buf, smartQuote(escape(v)))
|
||||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
||||||
tv == 'cdata' or tv == 'ctype' then
|
tv == 'cdata' or tv == 'ctype' then
|
||||||
puts(buf, tostring(v))
|
puts(buf, tostring(v))
|
||||||
elseif tv == 'table' and not self.ids[v] then
|
elseif tv == 'table' and not ids[v] then
|
||||||
local t = v
|
local t = v
|
||||||
|
|
||||||
if t == inspect.KEY or t == inspect.METATABLE then
|
local depth = options and options.depth
|
||||||
puts(buf, tostring(t))
|
if depth and level >= depth then
|
||||||
elseif self.level >= self.depth then
|
|
||||||
puts(buf, '{...}')
|
puts(buf, '{...}')
|
||||||
else
|
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 keys, keysLen, seqLen = getKeys(t)
|
||||||
|
|
||||||
|
local nextLevel = level + 1
|
||||||
puts(buf, '{')
|
puts(buf, '{')
|
||||||
self.level = self.level + 1
|
|
||||||
|
|
||||||
for i = 1, seqLen + keysLen do
|
for i = 1, seqLen + keysLen do
|
||||||
if i > 1 then puts(buf, ',') end
|
if i > 1 then puts(buf, ',') end
|
||||||
if i <= seqLen then
|
if i <= seqLen then
|
||||||
puts(buf, ' ')
|
puts(buf, ' ')
|
||||||
self:putValue(t[i])
|
putValue(t[i], buf, cycles, ids, nextLevel, options)
|
||||||
else
|
else
|
||||||
local k = keys[i - seqLen]
|
local k = keys[i - seqLen]
|
||||||
tabify(self)
|
tabify(buf, level + 1, options)
|
||||||
if isIdentifier(k) then
|
if isIdentifier(k) then
|
||||||
puts(buf, k)
|
puts(buf, k)
|
||||||
else
|
else
|
||||||
puts(buf, "[")
|
puts(buf, "[")
|
||||||
self:putValue(k)
|
putValue(k, buf, cycles, ids, nextLevel, options)
|
||||||
puts(buf, "]")
|
puts(buf, "]")
|
||||||
end
|
end
|
||||||
puts(buf, ' = ')
|
puts(buf, ' = ')
|
||||||
self:putValue(t[k])
|
putValue(t[k], buf, cycles, ids, nextLevel, options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local mt = getmetatable(t)
|
local mt = getmetatable(t)
|
||||||
if type(mt) == 'table' then
|
if type(mt) == 'table' then
|
||||||
if seqLen + keysLen > 0 then puts(buf, ',') end
|
if seqLen + keysLen > 0 then puts(buf, ',') end
|
||||||
tabify(self)
|
tabify(buf, level + 1, options)
|
||||||
puts(buf, '<metatable> = ')
|
puts(buf, '<metatable> = ')
|
||||||
self:putValue(mt)
|
putValue(mt, buf, cycles, ids, nextLevel, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.level = self.level - 1
|
|
||||||
|
|
||||||
if keysLen > 0 or type(mt) == 'table' then
|
if keysLen > 0 or type(mt) == 'table' then
|
||||||
tabify(self)
|
tabify(buf, level, options)
|
||||||
elseif seqLen > 0 then
|
elseif seqLen > 0 then
|
||||||
puts(buf, ' ')
|
puts(buf, ' ')
|
||||||
end
|
end
|
||||||
@ -248,7 +237,7 @@ function Inspector:putValue(v)
|
|||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
puts(buf, fmt('<%s %d>', tv, self:getId(v)))
|
puts(buf, fmt('<%s %d>', tv, getId(ids, v)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -256,28 +245,13 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function inspect.inspect(root, options)
|
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 = {}
|
local cycles = {}
|
||||||
countCycles(root, cycles)
|
countCycles(root, cycles)
|
||||||
|
|
||||||
local inspector = setmetatable({
|
local buf = { n = 0 }
|
||||||
buf = { n = 0 },
|
putValue(root, buf, cycles, {}, 0, options)
|
||||||
ids = {},
|
|
||||||
cycles = cycles,
|
|
||||||
depth = depth,
|
|
||||||
level = 0,
|
|
||||||
newline = newline,
|
|
||||||
indent = indent,
|
|
||||||
}, Inspector_mt)
|
|
||||||
|
|
||||||
inspector:putValue(root)
|
return concat(buf)
|
||||||
|
|
||||||
return table.concat(inspector.buf)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(inspect, {
|
setmetatable(inspect, {
|
||||||
|
114
inspect.tl
114
inspect.tl
@ -4,13 +4,12 @@ local record inspect
|
|||||||
_URL: string
|
_URL: string
|
||||||
_DESCRIPTION: string
|
_DESCRIPTION: string
|
||||||
_LICENSE: string
|
_LICENSE: string
|
||||||
KEY: table
|
|
||||||
METATABLE: table
|
|
||||||
|
|
||||||
record Options
|
record Options
|
||||||
depth: integer
|
depth: integer
|
||||||
newline: string
|
newline: string
|
||||||
indent: string
|
indent: string
|
||||||
|
override: function(any): string
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -41,8 +40,6 @@ inspect._LICENSE = [[
|
|||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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 tostring = tostring
|
||||||
local rep = string.rep
|
local rep = string.rep
|
||||||
@ -50,6 +47,7 @@ local match = string.match
|
|||||||
local char = string.char
|
local char = string.char
|
||||||
local gsub = string.gsub
|
local gsub = string.gsub
|
||||||
local fmt = string.format
|
local fmt = string.format
|
||||||
|
local concat = table.concat
|
||||||
|
|
||||||
local function rawpairs(t: table): function, table, nil
|
local function rawpairs(t: table): function, table, nil
|
||||||
return next, t, nil
|
return next, t, nil
|
||||||
@ -135,7 +133,7 @@ local function getKeys(t: table): {any}, integer, integer
|
|||||||
return keys, keysLen, seqLen
|
return keys, keysLen, seqLen
|
||||||
end
|
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 x is table then
|
||||||
if cycles[x] then
|
if cycles[x] then
|
||||||
cycles[x] = cycles[x] + 1
|
cycles[x] = cycles[x] + 1
|
||||||
@ -150,33 +148,8 @@ local function countCycles(x: any, cycles: {any:integer}): nil
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function puts(buf: table, str:string): nil
|
local function getId(ids: {any:integer}, v:any): string
|
||||||
buf.n = buf.n as integer + 1
|
local id: integer = ids[v]
|
||||||
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
|
|
||||||
if not id then
|
if not id then
|
||||||
local tv: string = type(v)
|
local tv: string = type(v)
|
||||||
id = (ids[tv] or 0) + 1
|
id = (ids[tv] or 0) + 1
|
||||||
@ -185,61 +158,77 @@ function Inspector:getId(v: any): string
|
|||||||
return tostring(id)
|
return tostring(id)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Inspector:putValue(v: any)
|
local function puts(buf: table, str:string): nil
|
||||||
local buf = self.buf
|
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)
|
local tv: string = type(v)
|
||||||
if tv == 'string' then
|
if tv == 'string' then
|
||||||
puts(buf, smartQuote(escape(v as string)))
|
puts(buf, smartQuote(escape(v as string)))
|
||||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
||||||
tv == 'cdata' or tv == 'ctype' then
|
tv == 'cdata' or tv == 'ctype' then
|
||||||
puts(buf, tostring(v as number))
|
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
|
local t = v as table
|
||||||
|
|
||||||
if t == inspect.KEY or t == inspect.METATABLE then
|
local depth = options and options.depth
|
||||||
puts(buf, tostring(t))
|
if depth and level >= depth then
|
||||||
elseif self.level >= self.depth then
|
|
||||||
puts(buf, '{...}')
|
puts(buf, '{...}')
|
||||||
else
|
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 keys, keysLen, seqLen = getKeys(t)
|
||||||
|
|
||||||
|
local nextLevel = level + 1
|
||||||
puts(buf, '{')
|
puts(buf, '{')
|
||||||
self.level = self.level + 1
|
|
||||||
|
|
||||||
for i = 1, seqLen + keysLen do
|
for i = 1, seqLen + keysLen do
|
||||||
if i > 1 then puts(buf, ',') end
|
if i > 1 then puts(buf, ',') end
|
||||||
if i <= seqLen then
|
if i <= seqLen then
|
||||||
puts(buf, ' ')
|
puts(buf, ' ')
|
||||||
self:putValue(t[i])
|
putValue(t[i], buf, cycles, ids, nextLevel, options)
|
||||||
else
|
else
|
||||||
local k = keys[i - seqLen]
|
local k = keys[i - seqLen]
|
||||||
tabify(self)
|
tabify(buf, level + 1, options)
|
||||||
if isIdentifier(k) then
|
if isIdentifier(k) then
|
||||||
puts(buf, k as string)
|
puts(buf, k as string)
|
||||||
else
|
else
|
||||||
puts(buf, "[")
|
puts(buf, "[")
|
||||||
self:putValue(k)
|
putValue(k, buf, cycles, ids, nextLevel, options)
|
||||||
puts(buf, "]")
|
puts(buf, "]")
|
||||||
end
|
end
|
||||||
puts(buf, ' = ')
|
puts(buf, ' = ')
|
||||||
self:putValue(t[k])
|
putValue(t[k], buf, cycles, ids, nextLevel, options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local mt = getmetatable(t)
|
local mt = getmetatable(t)
|
||||||
if type(mt) == 'table' then
|
if type(mt) == 'table' then
|
||||||
if seqLen + keysLen > 0 then puts(buf, ',') end
|
if seqLen + keysLen > 0 then puts(buf, ',') end
|
||||||
tabify(self)
|
tabify(buf, level + 1, options)
|
||||||
puts(buf, '<metatable> = ')
|
puts(buf, '<metatable> = ')
|
||||||
self:putValue(mt)
|
putValue(mt, buf, cycles, ids, nextLevel, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.level = self.level - 1
|
|
||||||
|
|
||||||
if keysLen > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
|
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 }
|
elseif seqLen > 0 then -- array tables have one extra space before closing }
|
||||||
puts(buf, ' ')
|
puts(buf, ' ')
|
||||||
end
|
end
|
||||||
@ -248,7 +237,7 @@ function Inspector:putValue(v: any)
|
|||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
puts(buf, fmt('<%s %d>', tv, self:getId(v)))
|
puts(buf, fmt('<%s %d>', tv, getId(ids, v)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -256,28 +245,13 @@ end
|
|||||||
|
|
||||||
|
|
||||||
function inspect.inspect(root: any, options: inspect.Options): string
|
function inspect.inspect(root: any, options: inspect.Options): string
|
||||||
options = options or {}
|
local cycles: {table: integer} = {}
|
||||||
|
|
||||||
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 = {}
|
|
||||||
countCycles(root, cycles)
|
countCycles(root, cycles)
|
||||||
|
|
||||||
local inspector = setmetatable({
|
local buf: table = { n = 0 }
|
||||||
buf = { n = 0 },
|
putValue(root, buf, cycles, {}, 0, options)
|
||||||
ids = {},
|
|
||||||
cycles = cycles,
|
|
||||||
depth = depth,
|
|
||||||
level = 0,
|
|
||||||
newline = newline,
|
|
||||||
indent = indent,
|
|
||||||
} as Inspector, Inspector_mt)
|
|
||||||
|
|
||||||
inspector:putValue(root)
|
return concat(buf as {string})
|
||||||
|
|
||||||
return table.concat(inspector.buf as {string})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(inspect, {
|
setmetatable(inspect, {
|
||||||
|
@ -262,6 +262,55 @@ describe( 'inspect', function()
|
|||||||
end)
|
end)
|
||||||
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()
|
describe('metatables', function()
|
||||||
|
|
||||||
it('includes the metatable as an extra hash attribute', function()
|
it('includes the metatable as an extra hash attribute', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user