diff --git a/inspect.lua b/inspect.lua
index ea2df3d..4fee019 100644
--- a/inspect.lua
+++ b/inspect.lua
@@ -170,7 +170,128 @@ local function processRecursive(process, item, path)
return processed
end
+
-------------------------------------------------------------------
+
+local Inspector = {}
+local Inspector_mt = {__index = Inspector}
+
+function Inspector:puts(...)
+ local args = {...}
+ local buffer = self.buffer
+ local len = #buffer
+ for i=1, #args do
+ len = len + 1
+ buffer[len] = tostring(args[i])
+ end
+end
+
+function Inspector:down(f)
+ self.level = self.level + 1
+ f()
+ self.level = self.level - 1
+end
+
+function Inspector:tabify()
+ self:puts("\n", string.rep(" ", self.level))
+end
+
+function Inspector:commaControl(needsComma)
+ if needsComma then self:puts(',') end
+ return true
+end
+
+function Inspector:alreadyVisited(v)
+ return self.ids[type(v)][v] ~= nil
+end
+
+function Inspector:getId(v)
+ local tv = type(v)
+ local id = self.ids[tv][v]
+ if not id then
+ id = self.maxIds[tv] + 1
+ self.maxIds[tv] = id
+ self.ids[tv][v] = id
+ end
+ return id
+end
+
+function Inspector:putKey(k)
+ if isIdentifier(k) then return self:puts(k) end
+ self:puts("[")
+ self:putValue(k)
+ self:puts("]")
+end
+
+function Inspector:putTable(t)
+ if self:alreadyVisited(t) then
+ self:puts('
')
+ elseif self.level >= self.depth then
+ self:puts('{...}')
+ else
+ if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
+
+ local dictKeys = getDictionaryKeys(t)
+ local length = #t
+ local mt = getmetatable(t)
+ local to_string_result = getToStringResultSafely(t, mt)
+
+ self:puts('{')
+ self:down(function()
+ if to_string_result then
+ self:puts(' -- ', escape(to_string_result))
+ if length >= 1 then self:tabify() end
+ end
+
+ local needsComma = false
+ for i=1, length do
+ needsComma = self:commaControl(needsComma)
+ self:puts(' ')
+ self:putValue(t[i])
+ end
+
+ for _,k in ipairs(dictKeys) do
+ needsComma = self:commaControl(needsComma)
+ self:tabify()
+ self:putKey(k)
+ self:puts(' = ')
+ self:putValue(t[k])
+ end
+
+ if mt then
+ needsComma = self:commaControl(needsComma)
+ self:tabify()
+ self:puts(' = ')
+ self:putValue(mt)
+ end
+ end)
+
+ 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('}')
+ end
+end
+
+function Inspector:putValue(v)
+ local tv = type(v)
+
+ if tv == 'string' then
+ self:puts(smartQuote(escape(v)))
+ elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then
+ self:puts(tostring(v))
+ elseif tv == 'table' then
+ self:putTable(v)
+ else
+ self:puts('<',tv,' ',self:getId(v),'>')
+ end
+end
+
+-------------------------------------------------------------------
+
function inspect.inspect(root, options)
options = options or {}
local depth = options.depth or math.huge
@@ -179,133 +300,18 @@ function inspect.inspect(root, options)
root = processRecursive(process, root, {})
end
- local tableAppearances = countTableAppearances(root)
+ local inspector = setmetatable({
+ depth = depth,
+ buffer = {},
+ level = 0,
+ ids = setmetatable({}, idsMetaTable),
+ maxIds = setmetatable({}, maxIdsMetaTable),
+ tableAppearances = countTableAppearances(root)
+ }, Inspector_mt)
- local buffer = {}
- local maxIds = setmetatable({}, maxIdsMetaTable)
- local ids = setmetatable({}, idsMetaTable)
- local level = 0
- local blen = 0 -- buffer length
+ inspector:putValue(root)
- local function puts(...)
- local args = {...}
- for i=1, #args do
- blen = blen + 1
- buffer[blen] = tostring(args[i])
- end
- end
-
- local function down(f)
- level = level + 1
- f()
- level = level - 1
- end
-
- local function tabify()
- puts("\n", string.rep(" ", level))
- end
-
- local function commaControl(needsComma)
- if needsComma then puts(',') end
- return true
- end
-
- local function alreadyVisited(v)
- return ids[type(v)][v] ~= nil
- end
-
- local function getId(v)
- local tv = type(v)
- local id = ids[tv][v]
- if not id then
- id = maxIds[tv] + 1
- maxIds[tv] = id
- ids[tv][v] = id
- end
- return id
- end
-
- local putValue -- forward declaration that needs to go before putTable & putKey
-
- local function putKey(k)
- if isIdentifier(k) then return puts(k) end
- puts( "[" )
- putValue(k, {})
- puts("]")
- end
-
- local function putTable(t)
- if alreadyVisited(t) then
- puts('')
- elseif level >= depth then
- puts('{...}')
- else
- if tableAppearances[t] > 1 then puts('<', getId(t), '>') end
-
- local dictKeys = getDictionaryKeys(t)
- local length = #t
- local mt = getmetatable(t)
- local to_string_result = getToStringResultSafely(t, mt)
-
- puts('{')
- down(function()
- if to_string_result then
- puts(' -- ', escape(to_string_result))
- if length >= 1 then tabify() end -- tabify the array values
- end
-
- local needsComma = false
- for i=1, length do
- needsComma = commaControl(needsComma)
- puts(' ')
- putValue(t[i])
- end
-
- for _,k in ipairs(dictKeys) do
- needsComma = commaControl(needsComma)
- tabify()
- putKey(k)
- puts(' = ')
- putValue(t[k])
- end
-
- if mt then
- needsComma = commaControl(needsComma)
- tabify()
- puts(' = ')
- putValue(mt)
- end
- end)
-
- if #dictKeys > 0 or mt then -- dictionary table. Justify closing }
- tabify()
- elseif length > 0 then -- array tables have one extra space before closing }
- puts(' ')
- end
-
- puts('}')
- end
-
- end
-
- -- putvalue is forward-declared before putTable & putKey
- putValue = function(v)
- local tv = type(v)
-
- if tv == 'string' then
- puts(smartQuote(escape(v)))
- elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then
- puts(tostring(v))
- elseif tv == 'table' then
- putTable(v)
- else
- puts('<',tv,' ',getId(v),'>')
- end
- end
-
- putValue(root, {})
-
- return table.concat(buffer)
+ return table.concat(inspector.buffer)
end
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })