Difference between revisions of "Module:DefInfo"
Jump to navigation
Jump to search
m |
(beta, slightly leaning towards alpha (there will be insects)) |
||
Line 1: | Line 1: | ||
+ | ---------------------------------------------- | ||
+ | -- 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 -- | -- 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 function | + | 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 | 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 | ||
end | end | ||
− | local function | + | local function merge_def(base_def_table, def_category, ignore_keys) |
− | local parent_name = | + | |
− | + | 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 | 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 | end | ||
− | local | + | 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 | end | ||
− | local | + | if not base_def_table then return nil end |
− | if | + | |
− | + | 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 | end | ||
− | local | + | --~ 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 | ||
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 | 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 | |
− | if not | + | mw.logObject(frame.args, "frame.args") |
− | + | mw.log("missing argument #1 (defName)") | |
+ | return nil | ||
end | end | ||
− | local | + | 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 | end | ||
− | + | ||
− | |||
end | end | ||
− | return | + | if type(prune) == "table" then mw.logObject(prune) end |
+ | return prune | ||
+ | end | ||
+ | |||
+ | function p.logObject(frame) | ||
+ | mw.logObject(get(frame)) | ||
end | end | ||
− | + | function p.dumpObject(frame) | |
− | mw.log(" | + | 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 | return p |
Revision as of 16:26, 16 April 2021
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