----------------------------------------------------------------------------------------------------------------------- -- inspect.lua - v1.1.1 (2011-01) -- 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 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 } local 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 function getToStringResultSafely(t, mt) local __tostring = type(mt) == 'table' and mt.__tostring local string, status if type(__tostring) == 'function' then status, string = pcall(__tostring, t) string = status and string or 'error: ' .. tostring(string) end return string end local Inspector = {} function Inspector:new(v, depth) local inspector = { buffer = {}, depth = depth, level = 0, counters = { ['function'] = 0, ['userdata'] = 0, ['thread'] = 0, ['table'] = 0 }, pools = { ['function'] = setmetatable({}, {__mode = "kv"}), ['userdata'] = setmetatable({}, {__mode = "kv"}), ['thread'] = setmetatable({}, {__mode = "kv"}), ['table'] = setmetatable({}, {__mode = "kv"}) } } setmetatable( inspector, { __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:alreadySeen(t) then self:puts('