Module:Item infobox: Difference between revisions

From Space Station 14 Wiki
Aliser (talk | contribs)
GOD I LOVE FOOD
 
Aliser (talk | contribs)
No edit summary
 
(4 intermediate revisions by the same user not shown)
Line 22: Line 22:


-- ==========================
-- ==========================
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)
local function starts_with(str, substr)
Line 58: Line 68:
local function table_contains(tbl, findFn)
local function table_contains(tbl, findFn)
     return table_find(tbl, findFn) ~= nil
     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
end


Line 103: Line 119:


     if table_length(edible_by_args) == 0 then
     if table_length(edible_by_args) == 0 then
         return
         return ""
     end
     end


Line 129: Line 145:
     -- returns the index ("order") of that entry.
     -- returns the index ("order") of that entry.
     -- throws if no param was found (ie not defined in the table).
     -- throws if no param was found (ie not defined in the table).
     function find_edible_by_order(param_name_lc)
     local function find_edible_by_order(param_name_lc)
         local index = table_find_index(edible_by_display_tbl, function(value)
         local index = table_find_index(edible_by_display_tbl, function(value)
             return value.param == param_name_lc
             return value.param == param_name_lc
         end)
         end)


         if index == nil then
         assert_not_nil(index, "failed to find edible by order: param name '" ..
            error("failed to find edible by order: param name '" ..
            param_name_lc .. "' if not defined in the edible by params table")
                param_name_lc .. "' if not defined in the edible by params table")
        end


         return index
         return index
Line 165: Line 179:
     local list_el = mw.html.create('ul')
     local list_el = mw.html.create('ul')


     function append_li(text)
     local function append_li(text)
         list_el
         list_el
             :tag("li")
             :tag("li")
Line 171: Line 185:
     end
     end


     function append_li_and_subli(li_text, subli_els)
     local function append_li_and_subli(li_text, subli_els)
         local li_el = mw.html.create("li")
         local li_el = mw.html.create("li")
             :wikitext(li_text)
             :wikitext(li_text)
Line 193: Line 207:
         append_li(edible_by_rest_entry.display[1])
         append_li(edible_by_rest_entry.display[1])
     else
     else
        -- some params selected
        for _, key_lc in ipairs(selected_params_lc) do
            local entry = table_find(edible_by_display_tbl, function(value)
                return value.param == key_lc
            end)
            if entry == nil then
                error("failed to generate edible by param: param '" ..
                    key_lc .. "' (lowercase) is not defined in the edible by display table")
            end
            append_li(entry.display)
        end
         if is_edible_by_rest then
         if is_edible_by_rest then
             -- edible by all, except those unselected
             -- 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.


             local display_unselected_entries = table_filter(edible_by_display_tbl, function(edible_by_display_entry)
            -- compile a list of those potentially excluded
                 local is_selected = table_contains(selected_params_lc, function(selected)
             local excluded_pool = table_filter(edible_by_display_tbl, function(entry)
                    return selected == edible_by_display_entry.param
                 return entry.param ~= edible_by_rest_param_name_lc
                end)
            end)
 
                local is_rest_param = edible_by_display_entry.param == edible_by_rest_param_name_lc
                if is_selected or is_rest_param then
                    return false
                end


                 return true
            -- find whose excluded (not selected)
            local excluded = table_filter(excluded_pool, function(entry)
                 return not table_contains_value(selected_params_lc, entry.param)
             end)
             end)


             local display_unselected_as_li_els = table_map(display_unselected_entries, function(value)
            -- format em as li els
             local excluded_as_li_els = table_map(excluded, function(value)
                 return mw.html.create("li")
                 return mw.html.create("li")
                     :wikitext(value.display)
                     :wikitext(value.display)
             end)
             end)


             append_li_and_subli(edible_by_rest_entry.display[2], display_unselected_as_li_els)
             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
     end
     end


     return list_el
     return tostring(list_el)
end
end


return p
return p

Latest revision as of 01:58, 4 April 2025

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