Module:DefInfo
Revision as of 16:26, 16 April 2021 by Dr. Strangelove (talk | contribs) (beta, slightly leaning towards alpha (there will be insects))
Dev version at Module:Test
---------------------------------------------- -- deal with differences in the environment -- ---------------------------------------------- if mw then ENV = "wiki" log = mw.log util = require("Module:Test/lib/util") search = require("Module:Test/lib/search") else ENV = "dev" mw = {} log = {} inspect = require './lib/inspect' util = require("./lib/util") search = require("./lib/search") function pinspect(tbl, title) util.hl(title) print(inspect(tbl)) end -- define used mw functions that don't exist in dev environment mw.logObject = function(obj, prefix) if prefix then assert(type(prefix) == "string") table.insert(log, prefix .. " = " .. inspect(obj)) else table.insert(log, inspect(obj)) end end mw.dumpObject = function(arg) return inspect(arg) end mw.log = function(arg) table.insert(log, arg) end end --------------- -- load data -- --------------- data = {} if ENV == "dev" then data["Biomes"] = loadfile("./data/BiomeDefs.lua")() data["Races"] = loadfile("./data/ThingDefs_Races.lua")() elseif ENV == "wiki" then data["Biomes"] = mw.loadData('Module:Test/data/biomes') data["Races"] = mw.loadData('Module:Test/data/races') end ------------------ -- virtual keys -- ------------------ -- this could be implemented with metatable events -- they get added in get(id_pair) local virtual_keys = { ["Races"] = { ["lives_in"] = function (race, biomes) local list = {} for biome_key, biome in pairs(biomes) do for _,animal in ipairs(biome.wildAnimals) do if race.defName == animal then table.insert(list, biome_key) end end end return list end } } ------------- -- private -- ------------- local function vardefine(name, value) local f_name = "vardefine" assert(var_name, string.format("bad argument #1 to '%s' (argument missing, name of variable to define)", f_name)) assert(var_name == "string", string.format("bad argument #1 to '%s' (string expected, got %s)", f_name, type(var_name))) assert(var_value, string.format("bad argument #2 to '%s' (argument missing, value to assign to variable)", f_name)) assert(var_value == "string" or var_value == "number", string.format("bad argument #2 to '%s' (string or number expected, got %s)", f_name, type(var_value))) frame:callParserFunction('#vardefine', var_name, var_value) end local function search_parent_def_table(key, def_table) local ParentName = getParentName(def_table) if not ParentName then return nil end local parentdef_table = search_table_recursive(ParentName, data) if not parentdef_table then return nil end local found = search_table_recursive(key, parentdef_table) if found then return found else found = search_parent_def_table(key, parentdef_table) if found then return found end end end local function merge_def(base_def_table, def_category, ignore_keys) local ancestors = {} local parent_name = base_def_table["ParentName"] local parent_table = data[def_category][parent_name] while parent_name do table.insert(ancestors, parent_name) parent_name = parent_table["ParentName"] parent_table = data[def_category][parent_name] end local inheritance_chain = util.shallowcopy(util.reverse_numeric_table(ancestors)) table.insert(inheritance_chain, base_def_table.defName) local merged = {} for i,v in ipairs(inheritance_chain) do util.overwrite_first_table_with_second(merged, data[def_category][inheritance_chain[i]], ignore_keys) end return merged end function get_def(defName) local base_def_table local def_category for catK,_ in pairs(data) do for defK,def in pairs(data[catK]) do if defK == defName then base_def_table = def def_category = catK end end end if not base_def_table then return nil end local def = merge_def(base_def_table, def_category, {"ParentName", "Abstract"}) -- add virtual keys if virtual_keys[def_category] then def._virtual = {} for k,func in pairs(virtual_keys[def_category]) do def._virtual[k] = func(def, data.Biomes) end end --~ mw.logObject(def, "def") return def end ------------ -- public -- ------------ local p = {} -- will expect frame.args[1] to be the label function p.getDefName(frame) local defName for catK,_ in pairs(data) do for defK,def in pairs(data[catK]) do if def["label"] then if string.upper(def["label"]) == string.upper(frame.args[1]) then defName = defK end end end end if not defName then mw.logObject(frame.args, "frame.args") mw.log(string.format("'%s' not found", frame.args[1])) end return defName end function p.count(frame) local query = p.query(frame) return #query end -- one function to rule them all, and in the darkness bind them function p.query(frame) -- implement shitloads of checks for arguments and the log so we know what's going on -- use them as a kind of usage guide (give as much info as possible) -- if wrong arguments are passed to private functions they will cause errors (they better) if not frame.args[1] then mw.logObject(frame.args, "frame.args") mw.log("missing argument #1 (defName)") return nil end local def = get_def(frame.args[1]) if not def then mw.logObject(frame.args, "frame.args") mw.log(string.format("bad argument #1 ('%s' not found)", frame.args[1])) return nil end local prune = def -- #frame.args won't work as expected, check the doc local arg_count = util.count(frame.args, "number") -- look at all the beautiful ifs! for i,arg in ipairs(frame.args) do -- frame.args are always strings on MediaWiki so convert the numbers back to numbers arg = tonumber(arg) or arg -- do stuff for additional arguments if i > 1 then -- special checks for the final argument if i == arg_count then -- sibling if frame.args["sibling"] then prune = search.conductor({nil, frame.args["sibling"]} , prune) if not prune then mw.logObject(frame.args, "frame.args") mw.log(string.format("bad argument 'sibling' ('%s' not found in '%s')", frame.args["sibling"], frame.args[i-1])) return nil else prune = prune.parent.table[arg] if not prune then mw.logObject(frame.args, "frame.args") mw.log(string.format("bad argument #%i ('%s' is not a sibling of '%s')", i, arg, frame.args["sibling"])) end end else prune = search.conductor(arg, prune) if not prune then mw.logObject(frame.args, "frame.args") mw.log(string.format("bad argument #%i ('%s' not found in '%s')", i, frame.args[i], frame.args[i-1])) return nil else prune = prune.value end end else prune = search.conductor(arg, prune) if not prune then mw.logObject(frame.args, "frame.args") mw.log(string.format("bad argument #%i ('%s' not found in '%s')", i, frame.args[i], frame.args[i-1])) return nil else prune = prune.value end end end end if type(prune) == "table" then mw.logObject(prune) end return prune end function p.logObject(frame) mw.logObject(get(frame)) end function p.dumpObject(frame) return mw.dumpObject(get(frame)) end local clock = string.format("os.clock(): %i ms", os.clock() * 1000) mw.log("--" .. string.rep("-", #clock) .. "--") mw.log("- " .. clock .. " -") mw.log("--" .. string.rep("-", #clock) .. "--") ---------------------------------------- -- simulate wiki log while developing -- ---------------------------------------- if ENV == "dev" then util.hl("log") for _,v in ipairs(log) do print(v) end end return p