Module:Logger

From [N8]
Jump to navigation Jump to search
Module documentation
This documentation is transcluded from Module:Logger/doc. [edit] [purge]
Module:Logger is required by Module:Enum.

This module is deprecated in favour of using mw.logObject(obj), but is still provided as an alternative. This module is a helper module to be used by other modules; it may not designed to be invoked directly. See GSWiki:Lua/Helper modules for a full list and more information. For a full list of modules using this helper click here

ModuleFunctionTypeUseExample
Loggerlog(table)tableDeprecated: usemw.logObject(obj) instead.

Logs the contents of the table to the console (does not expand subtables).

Notes:

  • Assumes all table indices can be represented as strings - using functions or tables as indices will result in non-specific log entries
  • This is best used by adding p.logger = require('Module:Logger') to the top of the module, then calling p.logger.log(obj) in the debug console on the module page
  • This module will only print to the debug console - it has no use when used outside of the development environment and should be removed/commented out before saving
deep_log(table)tableDeprecated: usemw.logObject(obj) instead. Logs the contents of the table to the console, expanding subtables. See above notes.
dumpObject(table, options)table, table/nilModified version of mw.dumpObject. Default values of the options are:
  • clean = false;     Removes the table#n and expands all tables even if the same table appears multiple times. The output is safe to load again by lua without further processing. Does not work for circular dependencies.
  • indentSize = 2;     Number of spaces/tabs to add for each indent level.
  • useTabs = false;     Use tabs to indent instead of spaces.
  • tabSize = 4;     Used to calculate the collapseLimit.
  • collapseLimit = 0;     Maximum length for collapsing a table onto a single line.
  • collapseArrays = true;     Allow arrays to collapse onto a single line.
  • wrapLongArrays = false;     Keep arrays collapsed and simply continue on a new line if the current line is longer then collapseLimit.
  • collapseObjects = true;     Allow key-value pairs to collapse onto a single line.
  • addEqualSignSpaces = false;     Add spaces around equal signes when the table is collapsed. Non collapsed table always have spaces.
  • addBracketSpaces = true;     Add spaces between the brackets and the data for collapsed tables i.e. { 'data' }.
  • numberPrecision = -1;     Number of decimals. Trailing zeros are trimmed. Negative numbers means let lua decide.
logObject(table, options)table, table/nilUses dumpObject and prints its result to the console.
logCleanTable(table, options)table, table/nilUses dumpObject and prints its results to the console but has the following default options changed:
  • clean = true
  • indentSize = 4
  • collapseLimit = 100
  • collapseArrays = true
  • collapseObjects = true

-- <nowiki>
local p = {}

function p.log(obj)
	if type(obj) ~= 'table' then
		mw.log('Argument is a '..type(obj)..', not a table')
		return
	end
	for i,v in pairs(obj) do
		mw.log(tostring(i)..'\t'..tostring(v))
	end
end

local function deep_log(obj, prefix)
	local pfix = ''
	if prefix then
		pfix = prefix..'.'
	end

	for i,v in pairs(obj) do
		mw.log(string.format('%s%s\t%s',pfix,tostring(i),tostring(v)))
		if type(v) == 'table' then
			deep_log(v,pfix..tostring(i))
		end
	end
end

function p.deep_log(obj)
	if type(obj) ~= 'table' then
		mw.log('Argument is a '..type(obj)..', not a table')
		return
	end
	deep_log(obj, nil)
end

local function default( input, defaults )
    input = input or {}
    local res = {}

    for k, v in pairs( input ) do
        res[k] = v
    end

    for k, v in pairs( defaults ) do
        if res[k] == nil then
            res[k] = v
        end
    end

    return res
end

local function isCleanName( str )
    return not (string.find( str, '^%d' ) or string.find( str, '[^_%w]' ))
end

function p.dumpObject( object, options )
    options = default( options, {
        clean = false,
        indentSize = 2,
        tabSize = 4,
        collapseLimit = 0,
        collapseArrays = true,
        wrapLongArrays = false,
        collapseObjects = true,
        useTabs = false,
        addEqualSignSpaces = false,
        addBracketSpaces = true,
        numberPrecision = -1
    } )
    local indentChar = options.useTabs and '\t' or ' '
    local doneTable = {}
    local doneObj = {}
    local ct = {}

    local function sorter( a, b )
        local ta, tb = type( a ), type( b )
        if ta ~= tb then
            return ta < tb
        end
        if ta == 'string' or ta == 'number' then
            return a < b
        end
        if ta == 'boolean' then
            return tostring( a ) < tostring( b )
        end
        return false -- Incomparable
    end

    local function _dumpObject( object, indent, expandTable )
        local tp = type( object )
        if tp == 'nil' or tp == 'boolean' then
            return tostring( object )
        elseif tp == 'number' then
            if options.numberPrecision < 0 then
                return tostring( object )
            else
                return (string.format('%.' .. options.numberPrecision .. 'f', object):gsub( '%.?0*$', '' ))
            end
        elseif tp == 'string' then
            return string.format( "%q", object )
        elseif tp == 'table' then
            if not doneObj[object] then
                local s = tostring( object )
                if string.find(s, '^table$') then
                    ct[tp] = ( ct[tp] or 0 ) + 1
                    doneObj[object] = 'table#' .. ct[tp]
                else
                    doneObj[object] = s
                    doneTable[object] = true
                end
            end
            if (doneTable[object] or not expandTable) and not options.clean then
                return doneObj[object]
            end
            doneTable[object] = true

            local colLen = options.useTabs and (options.tabSize * indent) or indent -- Collapsed string length
            local indentIndexes = {}
            local newLineIndexes = {}
            local equalSignIndexes = {}
            local arrayPartEndIndex = 1
            local ret = options.clean and { '', '', '{\n' } or { (doneObj[object] .. ' (#=' .. #object), '', ' {\n' }
            colLen = colLen + #ret[1]

            local function addIndent()
                ret[#ret + 1] = string.rep( indentChar, indent + options.indentSize )
                indentIndexes[#indentIndexes + 1] = #ret
            end

            local function addNewline()
                ret[#ret + 1] = ",\n"
                newLineIndexes[#newLineIndexes + 1] = #ret
            end

            local function addEqualSign()
                ret[#ret + 1] = " = "
                equalSignIndexes[#equalSignIndexes + 1] = #ret
            end

            local mt = getmetatable( object )
            if mt and not options.clean then
                addIndent()
                ret[#ret + 1] = 'metatable = '
                colLen = colLen + #ret[#ret]
                ret[#ret + 1] = _dumpObject( mt, indent + options.indentSize, false )
                colLen = colLen + #ret[#ret]
                addNewline()
            end

            local doneKeys = {}
            local count = 0

            for key, value in ipairs( object ) do
                doneKeys[key] = true
                addIndent()
                ret[#ret + 1] = _dumpObject( value, indent + options.indentSize, true )
                colLen = colLen + #ret[#ret]
                addNewline()

                count = count + 1
            end
            arrayPartEndIndex = #ret

            local keys = {}
            for key in pairs( object ) do
                if not doneKeys[key] then
                    keys[#keys + 1] = key
                    count = count + 1
                end
            end

            table.sort( keys, sorter )
            if not options.clean then ret[2] = ', n=' .. count .. ')' end
            colLen = colLen + #ret[2]

            for i = 1, #keys do
                local key = keys[i]
                addIndent()

                if options.clean and type( key ) == 'string' and isCleanName( key ) then
                    ret[#ret + 1] = key
                    colLen = colLen + #ret[#ret]
                    addEqualSign()
                else
                    ret[#ret + 1] = '['
                    ret[#ret + 1] = _dumpObject( key, nil, false )
                    colLen = colLen + #ret[#ret] + 2 -- +2 for the brackets []
                    ret[#ret + 1] = ']'
                    addEqualSign()
                end

                ret[#ret + 1] = _dumpObject( object[key], indent + options.indentSize, true )
                colLen = colLen + #ret[#ret] + 1
                addNewline()
            end

            ret[#ret + 1] = string.rep( indentChar, indent )
            indentIndexes[#indentIndexes + 1] = #ret
            ret[#ret + 1] = '}'

            colLen = colLen + 2 * (#newLineIndexes - 1) + (options.addBracketSpaces and 4 or 2)

            if
                (options.collapseArrays or options.collapseObjects) and
                colLen <= options.collapseLimit and
                not (options.collapseObjects == false and count > #object) and
                not (options.collapseArrays == false and #object > 0)
            then
                for _, i in ipairs( indentIndexes ) do
                    ret[i] = ''
                end
                for _, i in ipairs( newLineIndexes ) do
                    ret[i] = ', '
                end
                if not options.addEqualSignSpaces then
                    for _, i in ipairs( equalSignIndexes ) do
                        ret[i] = '='
                    end
                end

                ret[#ret - 1] = '' -- Indentation before closing bracket
                ret[3] = (options.addBracketSpaces and count > 0) and '{ ' or '{'
                if count > 0 then
                    if options.addBracketSpaces then ret[#ret] = ' }' end
                    ret[#ret - 2] = '' -- Last ', '
                end
            end

            if colLen > options.collapseLimit and options.collapseArrays and options.wrapLongArrays then
                local totalLen = options.collapseLimit -- Begin with collapse limit so that the first element keeps its indentation
                for _, i in ipairs( newLineIndexes ) do
                    local itemLen = #ret[i - 1] + 2 -- +2 for the ', '
                    if totalLen + itemLen - 1 >= options.collapseLimit then -- -1 to not count the space after the last ,
                        totalLen = indent + options.indentSize + itemLen
                    else
                        totalLen = totalLen + itemLen
                        ret[i - 2] = '' -- indentation
                        ret[i - 3] = ', '
                    end

                    if i >= arrayPartEndIndex then
                        break
                    end
                end
            end

            return table.concat( ret )
        else
            if not doneObj[object] then
                ct[tp] = ( ct[tp] or 0 ) + 1
                doneObj[object] = tostring( object ) .. '#' .. ct[tp]
            end
            return doneObj[object]
        end
    end

    return _dumpObject( object, 0, true )
end

function p.logCleanTable( object, options )
    mw.log( p.dumpObject( object, default( options, {
        clean = true,
        indentSize = 4,
        collapseLimit = 100,
        collapseArrays = true,
        collapseObjects = true,
        addEqualSignSpaces = false,
    } ) ) )
end

function p.logObject( object, options )
    mw.log( p.dumpObject( object, options ) )
end

return p
-- </nowiki>