I like having a depth limit though. IMHO it increases readability.
my alteration of your code keeps the depth as it is more readable, it just allows you to specify infinite depth as well.
ill try robins idea real quick to see how it looks with larger tables. do you know of anyway to get the hex value of the table with out just chopping of the first part of the tostring() output?
edit: i implemented robins idea, i looks pretty nice actually
added a function to get the hex string of a table
Code: Select all
local function tableHexStr(t)
return string.sub(tostring(t), 7)
end
and changed <following code> on line 147
to
Code: Select all
self:puts('} -- ', tableHexStr(t))
edit2:
just encase anyone is confused on where I am (e.g. i refer to line 147) here is the entier code
Code: Select all
-----------------------------------------------------------------------------------------------------------------------
-- inspect.lua - v1.0 (2011-04)
-- Enrique García Cota - enrique.garcia.cota [AT] gmail [DOT] com
-- human-readable representations of tables.
-- inspired by http://lua-users.org/wiki/TableSerialization
-----------------------------------------------------------------------------------------------------------------------
-- Apostrophizes the string if it has quotes, but not aphostrophes
-- Otherwise, it returns a regular quoted string
local function smartQuote(str)
if string.match( string.gsub(str,"[^'\"]",""), '^"+$' ) then
return "'" .. str .. "'"
end
return string.format("%q", str )
end
local function tableHexStr(t)
return string.sub(tostring(t), 7)
end
local controlCharsTranslation = {
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\\"] = "\\\\"
}
local function unescapeChar(c) return controlCharsTranslation[c] end
local function unescape(str)
local result, _ = string.gsub( str, "(%c)", unescapeChar )
return result
end
local function isIdentifier(str)
return string.match( str, "^[_%a][_%a%d]*$" )
end
local function isArrayKey(k, length)
return type(k)=='number' and 1 <= k and k <= length
end
local function isDictionaryKey(k, length)
return not isArrayKey(k, length)
end
local sortOrdersByType = {
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
['function'] = 5, ['userdata'] = 6, ['thread'] = 7
}
function sortKeys(a,b)
local ta, tb = type(a), type(b)
if ta ~= tb then return sortOrdersByType[ta] < sortOrdersByType[tb] end
if ta == 'string' or ta == 'number' then return a < b end
return false
end
local function getDictionaryKeys(t)
local length = #t
local keys = {}
for k,_ in pairs(t) do
if isDictionaryKey(k, length) then table.insert(keys,k) end
end
table.sort(keys, sortKeys)
return keys
end
local Inspector = {}
function Inspector:new(v, depth)
local inspector = setmetatable( { buffer = {}, depth = depth, level = 0, RefTbl = {} }, {
__index = Inspector,
__tostring = function(instance) return table.concat(instance.buffer) end
} )
return inspector:putValue(v)
end
function Inspector:puts(...)
local args = {...}
for i=1, #args do
table.insert(self.buffer, tostring(args[i]))
end
return self
end
function Inspector:tabify()
self:puts("\n", string.rep(" ", self.level))
return self
end
function Inspector:up()
self.level = self.level - 1
end
function Inspector:down()
self.level = self.level + 1
end
function Inspector:putComma(comma)
if comma then self:puts(',') end
return true
end
function Inspector:putTable(t)
if self.RefTbl[t] then
self:puts('<',tostring(t),'>')
elseif self.depth > 0 and self.level >= self.depth then
self:puts('{...}')
else
self.RefTbl[t] = true
self:puts('{')
self:down()
local length = #t
local mt = getmetatable(t)
local __tostring = type(mt) == 'table' and mt.__tostring
local string = type(__tostring) == 'function' and __tostring(t)
if type(string) == 'string' and #string > 0 then
self:puts(' -- ', unescape(string))
if length >= 1 then self:tabify() end -- tabify the array values
end
local comma = false
for i=1, length do
comma = self:putComma(comma)
self:puts(' '):putValue(t[i])
end
local dictKeys = getDictionaryKeys(t)
for _,k in ipairs(dictKeys) do
comma = self:putComma(comma)
self:tabify():putKey(k):puts(' = '):putValue(t[k])
end
if mt then
comma = self:putComma(comma)
self:tabify():puts('<metatable> = '):putValue(mt)
end
self:up()
if #dictKeys > 0 or mt then -- dictionary table. Justify closing }
self:tabify()
elseif length > 0 then -- array tables have one extra space before closing }
self:puts(' ')
end
self:puts('} -- ', tableHexStr(t))
self.RefTbl[t] = nil
end
return self
end
function Inspector:putValue(v)
local tv = type(v)
if tv == 'string' then
self:puts(smartQuote(unescape(v)))
elseif tv == 'number' or tv == 'boolean' then
self:puts(tostring(v))
elseif tv == 'table' then
self:putTable(v)
else
self:puts('<',tv,'>')
end
return self
end
function Inspector:putKey(k)
if type(k) == "string" and isIdentifier(k) then
return self:puts(k)
end
return self:puts( "[" ):putValue(k):puts("]")
end
local function inspect(t, depth)
depth = depth or 4
return tostring(Inspector:new(t, depth))
end
return inspect