Module:Item infobox
From Space Station 14 Wiki
Module documentation
|
---|
View or edit this documentation • (about module documentation) |
Contains partial implementation for {{Item infobox}}.
Edible by params
Edible by parameters are implemented in this module, entrypoint generate_edible_by
.
List of edible by params is defined by edible_by_display_tbl
.
Tests
Module:Item infobox/testcases/edible by
✅ All tests passed.
Name | Expected | Actual | |
---|---|---|---|
✅ | test_empty | ||
✅ | test_everyone | ||
✅ | test_everyone_except_other_options | ||
✅ | test_everyone_except_reptilians | ||
✅ | test_moth | ||
✅ | test_reptilian |
local p = {}
local getArgs = require('Module:Arguments').getArgs
local yesNo = require('Module:Yesno')
-- ==========================
local edible_by_rest_param_name_lc = "edible by rest"
-- A list of edible by parameters along with the texts to display for each.
-- Param names defined here must be lowercase.
--
-- "edible by rest" is a special case, hence the table format.
-- * If all options are selected, including "edible by rest" (ie food is edible by everyone),
-- then the first form will be used.
-- * If only some options are selected, including "edible by rest",
-- then the second form will be used, following by a list of unselected options.
local edible_by_display_tbl = {
{ param = "edible by reptilians", display = "Reptilians" },
{ param = "edible by moths", display = "Moth people" },
{ param = edible_by_rest_param_name_lc, display = { "Everyone", "Everyone, except:" } },
}
-- ==========================
local function assert_not_nil(value, error_message)
if value == nil then
if error_message == nil then
error("value is nil")
else
error(error_message)
end
end
end
local function starts_with(str, substr)
return string.sub(str, 1, string.len(substr)) == substr
end
local function ends_with(str, substr)
local substr_length = string.len(substr)
return string.sub(str, string.len(str) - substr_length + 1, string.len(str)) == substr
end
local function starts_with_insensitive(str, substr)
return starts_with(string.lower(str), string.lower(substr))
end
local function ends_with_insensitive(str, substr)
return ends_with(string.lower(str), string.lower(substr))
end
local function table_filter(tbl, filterFn)
local out = {}
for k, v in pairs(tbl) do
if filterFn(v, k, tbl) then out[k] = v end
end
return out
end
local function table_find(tbl, findFn)
for k, v in pairs(tbl) do
if findFn(v, k, tbl) then return v end
end
end
local function table_contains(tbl, findFn)
return table_find(tbl, findFn) ~= nil
end
local function table_contains_value(tbl, value)
return table_find(tbl, function(iter_value)
return iter_value == value
end) ~= nil
end
local function table_find_key(tbl, findFn)
for k, v in pairs(tbl) do
if findFn(v, k, tbl) then return k end
end
end
local function table_find_index(tbl, findFn)
for i, v in ipairs(tbl) do
if findFn(v, i, tbl) then return i end
end
end
local function table_map(tbl, mapFn)
local res = {}
for k, v in pairs(tbl) do
table.insert(res, mapFn(v, k, tbl))
end
return res
end
local function numeric_table_length(t)
local count = 0
for _ in ipairs(t) do count = count + 1 end
return count
end
local function table_length(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
-- ==========================
function p.generate_edible_by(frame)
local args = getArgs(frame)
local edible_by_args = table_filter(args, function(value, key)
return starts_with_insensitive(key, "edible by")
end)
if table_length(edible_by_args) == 0 then
return ""
end
local edible_by_rest_key = table_find_key(edible_by_args, function(value, key)
return ends_with_insensitive(key, "rest")
end)
-- save the edible by rest value to use later
local is_edible_by_rest = yesNo(edible_by_args[edible_by_rest_key])
-- generate a temp table made up only of numerical params to make it sortable.
-- get rid of unselected "edible by"s.
local selected_params_lc = {}
for key, value in pairs(edible_by_args) do
-- iterate over each key except edible by rest
if key ~= edible_by_rest_key then
-- check if its selected
if yesNo(value) then
table.insert(selected_params_lc, string.lower(key))
end
end
end
-- searches for a param name in the params table,
-- returns the index ("order") of that entry.
-- throws if no param was found (ie not defined in the table).
local function find_edible_by_order(param_name_lc)
local index = table_find_index(edible_by_display_tbl, function(value)
return value.param == param_name_lc
end)
assert_not_nil(index, "failed to find edible by order: param name '" ..
param_name_lc .. "' if not defined in the edible by params table")
return index
end
-- sort the temp table based on predefine order
table.sort(selected_params_lc, function(a, b)
return find_edible_by_order(a) > find_edible_by_order(b)
end)
-- render out the params
local edible_by_rest_entry = is_edible_by_rest
and table_find(edible_by_display_tbl, function(value)
return value.param == edible_by_rest_param_name_lc
end)
if is_edible_by_rest and edible_by_rest_entry == nil then
error(
"failed to generate edible by: edible by rest param is enabled, but it is not defined in the display table")
end
local selected_params_lc_len = numeric_table_length(selected_params_lc)
-- count total selected "edible by" params, including the edible by rest
local total_selected_params = selected_params_lc_len + (is_edible_by_rest and 1 or 0)
local display_table_len = numeric_table_length(edible_by_display_tbl)
local list_el = mw.html.create('ul')
local function append_li(text)
list_el
:tag("li")
:wikitext(text) -- relates to the li el, not the list el
end
local function append_li_and_subli(li_text, subli_els)
local li_el = mw.html.create("li")
:wikitext(li_text)
local subli_ul = mw.html.create('ul')
for _, node in ipairs(subli_els) do
subli_ul
:node(node)
end
li_el:
node(subli_ul)
list_el
:node(li_el)
end
if total_selected_params == display_table_len then
-- all params selected, edible by everyone
-- edible by rest is assumed to be on implicitly, cz otherwise the count won't match.
append_li(edible_by_rest_entry.display[1])
else
if is_edible_by_rest then
-- if edible by contains the rest option, we compile a list of those excluded from the display table.
-- those selected are excluded from the compiled list.
-- compile a list of those potentially excluded
local excluded_pool = table_filter(edible_by_display_tbl, function(entry)
return entry.param ~= edible_by_rest_param_name_lc
end)
-- find whose excluded (not selected)
local excluded = table_filter(excluded_pool, function(entry)
return not table_contains_value(selected_params_lc, entry.param)
end)
-- format em as li els
local excluded_as_li_els = table_map(excluded, function(value)
return mw.html.create("li")
:wikitext(value.display)
end)
append_li_and_subli(edible_by_rest_entry.display[2], excluded_as_li_els)
else
-- if edible by doesn't contain the rest option, then its a regular list
for _, param_name_lc in ipairs(selected_params_lc) do
local entry = table_find(edible_by_display_tbl, function(entry)
return entry.param == param_name_lc
end)
assert_not_nil(entry, "failed to generate edible by param: param '" ..
param_name_lc .. "' (lowercase) is not defined in the edible by display table")
append_li(entry.display)
end
end
end
return tostring(list_el)
end
return p