Editing Module:Test
Jump to navigation
Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
− | + | ---@diagnostic disable: lowercase-global | |
− | local | + | local p = {} |
− | |||
− | |||
− | |||
− | |||
------------------------------------------------------------------ | ------------------------------------------------------------------ | ||
Line 11: | Line 7: | ||
if mw then | if mw then | ||
− | + | ENV = "wiki" | |
log = mw.log | log = mw.log | ||
− | |||
− | + | util = require("Module:Test/lib/util") | |
− | + | search = require("Module:Test/lib/search") | |
− | + | else | |
+ | ENV = "dev" | ||
− | + | mw = {} | |
− | log | + | log = {} |
− | + | inspect = require './module/lib/inspect' | |
− | + | util = require("./module/lib/util") | |
− | + | search = require("./module/lib/search") | |
+ | diet = require("./module/data/diet") | ||
− | + | function pp(tbl, title) -- pretty print tables | |
− | + | util.hl(title) | |
− | + | print(inspect(tbl)) | |
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | logObject = function(obj, prefix) | + | -- (re)define used mw functions that don't exist in dev environment |
+ | mw.logObject = function(obj, prefix) | ||
if prefix then | if prefix then | ||
assert(type(prefix) == "string") | assert(type(prefix) == "string") | ||
− | table.insert( | + | table.insert(log, prefix .. " = " .. inspect(obj)) |
else | else | ||
− | table.insert( | + | table.insert(log, inspect(obj)) |
end | end | ||
end | end | ||
− | function | + | mw.dumpObject = function(arg) |
− | + | return inspect(arg) | |
− | |||
end | end | ||
− | + | mw.log = function(arg) | |
+ | table.insert(log, arg) | ||
+ | end | ||
+ | end | ||
− | + | --------------- | |
+ | -- load data -- | ||
+ | --------------- | ||
− | + | if ENV == "dev" then | |
− | + | data = loadfile("./data.lua")() | |
+ | -- diet = loadfile("./diet.lua")() | ||
+ | elseif ENV == "wiki" then | ||
+ | data = mw.loadData('Module:Test/data') | ||
+ | end | ||
+ | |||
+ | version = data.version | ||
+ | |||
+ | ------------------ | ||
+ | -- virtual keys -- | ||
+ | ------------------ | ||
− | + | local virtual_store = {} | |
− | + | local virtual_keys = { | |
− | + | ["Pawn"] = { | |
− | |||
− | + | function (def) | |
+ | virtField = "lives_in" | ||
+ | biomes = {} | ||
+ | for k,v in pairs(data) do | ||
+ | prefix = string.match(k, '(.+):') | ||
+ | if prefix == "BiomeDef" then | ||
+ | table.insert(biomes, v) | ||
+ | end | ||
+ | end | ||
− | end | + | local list = {} |
+ | for _,biome in pairs(biomes) do | ||
+ | for animal,_ in pairs(biome.wildAnimals or {}) do | ||
+ | if def.defName == animal then | ||
+ | table.insert(list, biome.label) | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | if #list > 0 then | ||
+ | def._virtual_[virtField] = list | ||
+ | end | ||
+ | end, | ||
+ | |||
+ | function (def) | ||
+ | virtField = "diet" | ||
+ | diet = def.race.foodType | ||
+ | flags = {} | ||
+ | virtual_store.diet = {} | ||
+ | |||
+ | for _,foodType in ipairs(diet) do | ||
+ | if type(util.diet.foodType[foodType]) == "boolean" then | ||
+ | flags[foodType] = true | ||
+ | else | ||
+ | for foodItem,_ in pairs(util.diet.foodType[foodType]) do | ||
+ | flags[foodItem] = true | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | for flag,_ in pairs(flags) do | ||
+ | table.insert(virtual_store.diet, flag) | ||
+ | end | ||
+ | |||
+ | if #virtual_store.diet > 0 then | ||
+ | def._virtual_[virtField] = virtual_store.diet | ||
+ | end | ||
+ | end, | ||
+ | |||
+ | } | ||
+ | } | ||
----------------------- | ----------------------- | ||
Line 70: | Line 124: | ||
----------------------- | ----------------------- | ||
− | function | + | local function vardefine(name, value) |
− | assert(name, " | + | local f_name = "vardefine" |
− | assert(type(name) == "string", string.format(" | + | frame = mw.getCurrentFrame() |
− | assert(value, " | + | assert(name, string.format("bad argument #1 to '%s' (argument missing, name of variable to define)", f_name)) |
− | assert | + | assert(type(name) == "string", string.format("bad argument #1 to '%s' (string expected, got %s)", f_name, type(name))) |
− | + | assert(value, string.format("bad argument #2 to '%s' (argument missing, value to assign to variable)", f_name)) | |
+ | -- assert(value == "string" or value == "number", string.format("bad argument #2 to '%s' (string or number expected, got %s)", f_name, type(value))) | ||
+ | |||
frame:callParserFunction('#vardefine', name, value) | frame:callParserFunction('#vardefine', name, value) | ||
end | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | function | + | local function mergeParents(baseDef, ignoreKeys) |
local ancestorIDs = {} | local ancestorIDs = {} | ||
local mergedDef = {} | local mergedDef = {} | ||
Line 97: | Line 144: | ||
local parentID = def._.DefCategory .. ":" .. def._.ParentName | local parentID = def._.DefCategory .. ":" .. def._.ParentName | ||
table.insert(ancestorIDs, parentID) | table.insert(ancestorIDs, parentID) | ||
− | def = | + | def = data[parentID] |
end | end | ||
− | ancestorIDs = | + | ancestorIDs = util.table.reverse(ancestorIDs) |
table.insert(ancestorIDs, baseDef._.DefCategory .. ":" .. baseDef.defName) | table.insert(ancestorIDs, baseDef._.DefCategory .. ":" .. baseDef.defName) | ||
for _,parentID in ipairs(ancestorIDs) do | for _,parentID in ipairs(ancestorIDs) do | ||
− | + | util.table.overwrite(mergedDef, data[parentID], ignoreKeys) | |
end | end | ||
Line 110: | Line 157: | ||
end | end | ||
− | |||
− | |||
+ | function getDef(defIDsuffix, defIDprefix) | ||
local ignoreKeys = {"Abstract", "Name", "ParentName"} | local ignoreKeys = {"Abstract", "Name", "ParentName"} | ||
local baseDef | local baseDef | ||
− | local def | + | local mergedDef |
+ | |||
+ | if defIDprefix then | ||
+ | local defID = defIDprefix .. ":" .. defIDsuffix | ||
+ | baseDef = data[defID] | ||
+ | assert(not baseDef, string.format("getDef: Def '%s' not found", defID)) | ||
+ | else | ||
+ | for defID,def in pairs(data) do | ||
+ | -- WARNING: this depends on there not being any preexisting colons in the relevant substrings | ||
+ | prefix = string.match(defID, '(.+):') | ||
+ | suffix = string.match(defID, ':(.+)') | ||
+ | if suffix == defIDsuffix then | ||
+ | assert(not baseDef, string.format("getDef: Def conflict (more than one '%s')", defIDsuffix)) | ||
+ | baseDef = def | ||
+ | end | ||
+ | end | ||
+ | assert(baseDef, string.format("getDef: Def '%s' not found", defIDsuffix)) | ||
+ | end | ||
− | + | mergedDef = mergeParents(baseDef, ignoreKeys) | |
− | + | if virtual_keys[mergedDef.category] then | |
− | + | mergedDef._virtual_ = {} | |
− | + | for k,func in ipairs(virtual_keys[mergedDef.category]) do | |
− | + | func(mergedDef) | |
− | |||
− | |||
− | |||
end | end | ||
end | end | ||
− | + | return mergedDef | |
+ | end | ||
− | |||
− | + | ---------------------- | |
+ | -- public interface -- | ||
+ | ---------------------- | ||
− | + | local function setMeta(table, parentKey) | |
− | + | local mw = {} | |
+ | for k,v in pairs(table) do | ||
− | |||
− | |||
− | |||
− | |||
− | |||
if type(v) == 'table' then | if type(v) == 'table' then | ||
− | + | setMeta(v, parentKey .. "_" .. k) | |
else | else | ||
− | + | mw[k] = parentKey .. "_" .. k | |
end | end | ||
end | end | ||
+ | setmetatable(table, mw) | ||
+ | end | ||
− | |||
− | |||
− | local function | + | local function defineRecursive(tbl) |
for k,v in pairs(tbl) do | for k,v in pairs(tbl) do | ||
if type(v) ~= 'table' then | if type(v) ~= 'table' then | ||
local mt = getmetatable(tbl) | local mt = getmetatable(tbl) | ||
− | log(string.format( | + | mw.log(string.format("{{#vardefine:%s|%s}}", mt[k], v)) |
− | + | vardefine(mt[k], v) | |
− | else | + | else |
− | + | defineRecursive(v) | |
end | end | ||
end | end | ||
end | end | ||
− | |||
− | |||
− | |||
− | function | + | -- procedure |
− | local | + | function p.define(frame) |
− | if type( | + | local argLen = util.table.count(frame.args, "number") -- #frame.args won't work as expected, check the doc |
− | + | local tbl = p.query(frame) | |
+ | if type(tbl) == 'table' then | ||
+ | setMeta(tbl, frame.args[argLen]) | ||
+ | defineRecursive(tbl) | ||
end | end | ||
end | end | ||
− | |||
− | + | function p.getDefName(frame) | |
+ | local defName | ||
+ | local label = frame.args[1] | ||
− | if not | + | if not label then |
− | logObject(frame.args, | + | mw.logObject(frame.args, "frame.args") |
+ | mw.log("getDefName: missing argument #1 (label)") | ||
return nil | return nil | ||
end | end | ||
− | + | for defID,def in pairs(data) do | |
+ | if string.upper(def.label or "") == string.upper(label) then | ||
+ | defName = def.defName | ||
+ | end | ||
+ | end | ||
+ | |||
+ | if not defName then | ||
+ | mw.logObject(frame.args, "frame.args") | ||
+ | mw.log(string.format("getDefName: '%s' not found", label)) | ||
+ | end | ||
+ | |||
+ | return defName | ||
+ | end | ||
+ | |||
− | if not | + | function p.count(frame) |
− | logObject(frame.args, | + | local query = p.query(frame) |
+ | if type(query) == 'table' then | ||
+ | return #query | ||
+ | else | ||
+ | return type(query) | ||
+ | end | ||
+ | end | ||
+ | |||
+ | |||
+ | function p.query(frame) | ||
+ | local argLen = util.table.count(frame.args, "number") -- #frame.args won't work as expected, check the doc | ||
+ | |||
+ | -- implement expressive argument checks so we know what's going on | ||
+ | -- use them as a kind of usage guide (give as much info as possible) | ||
+ | |||
+ | if not frame.args[1] then | ||
+ | mw.logObject(frame.args, "frame.args") | ||
+ | mw.log("query: missing argument #1 (defName or Name, for abstract Defs)") | ||
return nil | return nil | ||
end | end | ||
− | if def | + | local def = getDef(frame.args[1]) |
− | logObject( | + | |
+ | if not def then | ||
+ | mw.logObject(frame.args, "frame.args") | ||
+ | mw.log(string.format("query: bad argument #1 ('%s' not found)", frame.args[1])) | ||
return nil | return nil | ||
end | end | ||
− | local | + | local prune = def |
for i,arg in ipairs(frame.args) do -- arguments | for i,arg in ipairs(frame.args) do -- arguments | ||
+ | |||
arg = tonumber(arg) or arg -- frame.args are always strings on MediaWiki so convert back the numbers | arg = tonumber(arg) or arg -- frame.args are always strings on MediaWiki so convert back the numbers | ||
− | if i == argLen | + | -- NOTE: might consider doing something about the if tree (trim it down a bit) |
− | + | ||
− | + | if i > 1 then -- additional arguments | |
− | + | ||
− | + | if i == argLen then -- if final argument | |
− | + | ||
− | + | if frame.args["sibling"] then -- sibling | |
− | + | prune = search.conductor({nil, frame.args["sibling"]} , prune) | |
− | + | if not prune then | |
+ | mw.logObject(frame.args, "frame.args") | ||
+ | mw.log(string.format("query: 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("query: 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("query: bad argument #%i ('%s' not found in '%s')", i, frame.args[i], frame.args[i-1])) | ||
+ | return nil | ||
+ | else | ||
+ | prune = prune.value | ||
+ | end | ||
+ | end -- sibling | ||
+ | |||
+ | else -- if not final argument | ||
+ | prune = search.conductor(arg, prune) | ||
+ | if not prune then | ||
+ | mw.logObject(frame.args, "frame.args") | ||
+ | mw.log(string.format("query: bad argument #%i ('%s' not found in '%s')", i, frame.args[i], frame.args[i-1])) | ||
return nil | return nil | ||
+ | else | ||
+ | prune = prune.value | ||
end | end | ||
end | end | ||
− | |||
− | + | end -- additional arguments | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end -- for arguments | end -- for arguments | ||
− | if type( | + | if type(prune) == "table" then |
− | + | setMeta(prune, frame.args[argLen]) | |
− | + | defineRecursive(prune) | |
− | |||
− | |||
− | |||
end | end | ||
− | + | return prune | |
− | return | ||
end | end | ||
− | ------------------------------------ | + | --------------------------------- |
− | -- | + | -- simulate module invocation -- |
− | ------------------------------------ | + | --------------------------------- |
+ | |||
+ | local simframe = { ["args"] = {} } | ||
+ | frame = frame or simframe | ||
+ | |||
+ | --~ simframe.args[1] = "Penoxycyline" | ||
+ | simframe.args[1] = "Mech_Scyther" | ||
+ | simframe.args[2] = "tools" | ||
+ | -- simframe.args[3] = "1" | ||
+ | --~ simframe.args[3] = 3 | ||
+ | |||
+ | if ENV == "dev" then | ||
+ | |||
+ | print(p.query(frame)) | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | if | + | local clock = string.format("os.clock(): %i ms", os.clock() * 1000) |
− | + | mw.log("--" .. string.rep("-", #clock) .. "--") | |
− | for _,v in ipairs( | + | 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) | print(v) | ||
end | end | ||
end | end | ||
− | + | return p -- return module | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |