Skip to content

Pretty Table Dumper

stevedonovan edited this page Feb 17, 2013 · 1 revision

Unlike moon.p, this outputs in Moonscript format. It detects cycles and the output can be limited. Does not do indentation, however. Primarily intended as a debugging tool, not for serious serialization.

---- moondump.moon ----
-- A reasonably bullet-proof table dumper that writes out in Moon syntax;
-- can limit the number of items dumped out, and cycles are detected.
-- No attempt at doing pretty indentation here, but it does try to produce
-- 'nice' looking output by separating the hash and the array part.
--
--  dump = require 'moondump'
--  ...
--  print dump t  -- default, limit 1000, respect tostring
--  print dump t, limit:10000,raw:true   -- ignore tostring
--
quote  = (v) ->
    if type(v) == 'string'
        '%q'\format(v)
    else
        tostring(v)

--- return a string representation of a Lua value.
-- Cycles are detected, and a limit on number of items can be imposed.
-- @param t the table
-- @param options
--    limit on items, default 1000
--    raw ignore tostring
-- @return a string
(t,options) ->
    options = options or {}
    limit = options.limit or 1000
    buff = tables:{[t]:true}
    k,tbuff = 1,nil

    put = (v) ->
        buff[k] = v
        k += 1

    put_value = (value) ->
        if type(value) ~= 'table'
            put quote value
            if limit and k > limit
                buff[k] = "..."
                error "buffer overrun"
        else
            if not buff.tables[value] -- cycle detection!
                buff.tables[value] = true
                tbuff value
            else
                put "<cycle>"
        put ','

    tbuff = (t) ->
        mt = getmetatable t unless options.raw
        if type(t) ~= 'table' or mt and mt.__tostring
            put quote t
        else
            put '{'
            indices = #t > 0 and {i,true for i = 1,#t}
            for key,value in pairs t -- first do the hash part
                if indices and indices[key] then continue
                if type(key) ~= 'string' then
                    key = '['..tostring(key)..']'
                elseif key\match '%s'
                    key = quote key
                put key..':'
                put_value value

            if indices -- then bang out the array part
                for v in *t
                    put_value v

            if buff[k - 1] == "," then k -= 1
            put '}'


    -- we pcall because that's the easiest way to bail out if there's an overrun.
    pcall tbuff,t
    table.concat(buff)