Module:DebugUtil

local ScriptUtil = require "Module:ScriptUtil"

local pack = function (...) return {n = select('#', ...), ...} end

local timed = function (f) return function (...) local t0 = os.clock local ret = pack(f(...)) mw.log(os.clock - t0) return unpack(ret, 1, ret.n)	end end

local cargo_counted = function (f) local query = mw.ext.cargo.query return function (...) local c = 0 mw.ext.cargo.query = function (...) c = c + 1 return query(...) end local ret = pack(f(...)) mw.ext.cargo.query = query mw.log(c) return unpack(ret, 1, ret.n)	end end

-- Returns a string representation of the table t, recursively calls itself for nested table keys and values local getTableString; do	local type = type local tostring = tostring local serfunc = function (x) local typ = type(x) if typ == 'boolean' then return x and 'true' or 'false' elseif typ == 'number' then return tostring(x) elseif typ == 'string' then return ('%q'):format(x) elseif typ == 'table' then return getTableString(x) elseif typ == nil then return 'nil' else return "--" .. typ .. "" end end getTableString = function (t) if not t then return 'nil' end if not next(t) then return '{ }' end local str = {} local keys = {} for k in next, t do		keys[#keys + 1] = {k, serfunc(k)} end table.sort(keys, function (a, b) return a[2] < b[2] end) for i = 1, #keys do		str[i] = ('[%s] = %s'):format(keys[i][2], serfunc(rawget(t, keys[i][1]))) end return '{' .. table.concat(str, ', ') .. '}' end; end

local dumpObject = function (object) 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, expandTable ) local tp = type( object ) if tp == 'number' or tp == 'nil' or tp == 'boolean' then return tostring( object ) elseif tp == 'string' then return string.format( "%q", object ) elseif tp == 'table' then if not doneObj[object] then local s = tostring( object ) if 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 then return doneObj[object] end doneTable[object] = true

local ret = { doneObj[object], ' { ' } local mt = getmetatable( object ) if mt then ret[#ret + 1] = 'metatable = ' ret[#ret + 1] = _dumpObject( mt, false ) ret[#ret + 1] = ', ' end

local doneKeys = {} for key, value in ipairs( object ) do				doneKeys[key] = true ret[#ret + 1] = _dumpObject( value, true ) ret[#ret + 1] = ', ' end local keys = {} for key in pairs( object ) do				if not doneKeys[key] then keys[#keys + 1] = key end end table.sort( keys, sorter ) for i = 1, #keys do				local key = keys[i] ret[#ret + 1] = '[' ret[#ret + 1] = _dumpObject( key, false ) ret[#ret + 1] = '] = ' ret[#ret + 1] = _dumpObject( object[key], true ) ret[#ret + 1] = ', ' end

if #ret == 2 then ret[#ret + 1] = '}' else ret[#ret] = ' }' 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, true ) end

local equal; do	local next, rawequal, rawget, type = next, rawequal, rawget, type equal = function (x, y)	local t1 = type(x) local t2 = type(y) if t1 ~= t2 then return false end if rawequal(x, y) then return true elseif t1 ~= 'table' then return false end for kx, vx in next, x do		if not equal(vx, rawget(y, kx)) then return false end end for ky in next, y do		if rawequal(rawget(x, ky), nil) then return false end end return true end; end

local log = function (frame) mw.log(frame.args[1]) end

local preprocessWithUnsaved = function(str,p,title) local debugFrame = mw.getCurrentFrame local moduleToCall,functionToCall = mw.ustring.match( str, "#invoke:%s*([^}|]*)%s*|%s*([^}|]*)%s*" ) moduleToCall = mw.text.trim(moduleToCall) functionToCall = mw.text.trim(functionToCall) if ("Module:"..moduleToCall) == debugFrame:getTitle then --Piggybacking on ScriptUtil's template processor instead of writing a processor templified_str = mw.ustring.gsub(str,"#invoke:([^}|]*)|[^|}]*","%1") local t = ScriptUtil.Template.newFromWikitext(templified_str) local args = t:getArgs return p[functionToCall](debugFrame:newChild{title = title,args = args}) else local testedFrame if context_title then testedFrame = debugFrame:newChild{title = title} else testedFrame = debugFrame end return testedFrame:preprocess(str) end end

return { timed = timed, cargo_counted = cargo_counted, dumpObject = dumpObject, equal = equal, log = log, preprocessWithUnsaved = preprocessWithUnsaved, }