allow using inspect inside __tostring metamethods without errors

This commit is contained in:
Enrique García Cota 2018-04-06 23:14:00 +02:00
parent bebc212672
commit b611db6bfa
2 changed files with 10 additions and 43 deletions

View File

@ -124,16 +124,6 @@ local function getNonSequentialKeys(t)
return keys, keysLength, sequenceLength return keys, keysLength, sequenceLength
end end
local function getToStringResultSafely(t, mt)
local __tostring = type(mt) == 'table' and rawget(mt, '__tostring')
local str, ok
if type(__tostring) == 'function' then
ok, str = pcall(__tostring, t)
str = ok and str or 'error: ' .. tostring(str)
end
if type(str) == 'string' and #str > 0 then return str end
end
local function countTableAppearances(t, tableAppearances) local function countTableAppearances(t, tableAppearances)
tableAppearances = tableAppearances or {} tableAppearances = tableAppearances or {}
@ -254,15 +244,9 @@ function Inspector:putTable(t)
local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t) local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
local mt = getmetatable(t) local mt = getmetatable(t)
local toStringResult = getToStringResultSafely(t, mt)
self:puts('{') self:puts('{')
self:down(function() self:down(function()
if toStringResult then
self:puts(' -- ', escape(toStringResult))
if sequenceLength >= 1 then self:tabify() end
end
local count = 0 local count = 0
for i=1, sequenceLength do for i=1, sequenceLength do
if count > 0 then self:puts(',') end if count > 0 then self:puts(',') end

View File

@ -363,32 +363,17 @@ describe( 'inspect', function()
]]), inspect(bar)) ]]), inspect(bar))
end) end)
it('includes the __tostring metamethod if it exists', function() it('can be used on the __tostring metamethod of a table without errors', function()
local foo = { foo = 1, __tostring = function() return 'hello\nworld' end } local f = function(x) return inspect(x) end
local bar = setmetatable({a = 1}, foo) local tbl = setmetatable({ x = 1 }, { __tostring = f })
assert.equals(unindent([[ assert.equals(unindent([[
{ -- hello\nworld {
a = 1, x = 1,
<metatable> = { <metatable> = {
__tostring = <function 1>, __tostring = <function 1>
foo = 1
} }
} }
]]), inspect(bar)) ]]), tostring(tbl))
end)
it('includes an error string if __tostring metamethod throws an error', function()
local foo = { foo = 1, __tostring = function() error('hello', 0) end }
local bar = setmetatable({a = 1}, foo)
assert.equals(unindent([[
{ -- error: hello
a = 1,
<metatable> = {
__tostring = <function 1>,
foo = 1
}
}
]]), inspect(bar))
end) end)
it('does not allow collecting weak tables while they are being inspected', function() it('does not allow collecting weak tables while they are being inspected', function()
@ -397,18 +382,16 @@ describe( 'inspect', function()
local shimMetatable = { local shimMetatable = {
__mode = 'v', __mode = 'v',
__index = function() return {} end, __index = function() return {} end,
__tostring = function() collectgarbage() return 'shim' end
} }
local function shim() return setmetatable({}, shimMetatable) end local function shim() return setmetatable({}, shimMetatable) end
local t = shim() local t = shim()
t.key = shim() t.key = shim()
assert.equals(unindent([[ assert.equals(unindent([[
{ -- shim {
key = { -- shim key = {
<metatable> = <1>{ <metatable> = <1>{
__index = <function 1>, __index = <function 1>,
__mode = "v", __mode = "v"
__tostring = <function 2>
} }
}, },
<metatable> = <table 1> <metatable> = <table 1>