Module:Util

From Path of Exile 2 Wiki
Revision as of 17:43, 28 December 2015 by >OmegaK2 (function for safeguarding functions)
Jump to navigation Jump to search
Module documentation[view] [edit] [history] [purge]


This is a meta module.

This module is meant to be used only by other modules. It should not be invoked in wikitext.

Lua logo

This module depends on the following other modules:

Overview

Provides utility functions for programming modules.

Structure

Group Description
util.cast utilities for casting values (i.e. from arguments)
util.html shorthand functions for creating some html tags
util.misc miscellaneous functions

Usage

This module should be loaded with require().

-- Utility stuff

local xtable = require('Module:Table')
local util = {}

-- ----------------------------------------------------------------------------
-- util.cast
-- ----------------------------------------------------------------------------

util.cast = {}
util.cast.bool_false = {'false', '0', 'disabled', 'off', 'no', ''}

function util.cast.boolean(value)
    -- Takes an abitary value and casts it to a bool value
    -- 
    -- for strings false will be according to util.cast.bool_false
    local t = type(value)
    if t == 'nil' then
        return false
    elseif t == 'boolean' then
        return value
    elseif t == 'number' then
        if value == 0 then return false end
        return true
    elseif t == 'string' then
        local tmp = string.lower(value)
        for _, v in ipairs(util.cast.bool_false) do
            if v == tmp then
                return false
            end
        end
        return true
    else
        error(string.format('value "%s" of type "%s" is not a boolean', value, t))
    end
    
end

function util.cast.number(value, args)
    -- Takes an abitary value and attempts to cast it to int
    --
    -- args:
    --  default: for strings, if default is nil and the conversion fails, an error will be returned
    --  min: error if <min
    --  max: error if >max
    if args == nil then
        args = {}
    end
    
    local t = type(value)
    local val
    
    if t == 'nil' then
        val = nil
    elseif t == 'boolean' then
        if value then
            val = 1
        else
            val = 0
        end
    elseif t == 'number' then
        val = value
    elseif t == 'string' then
        val = tonumber(value)
    end
    
    if val == nil then
        if args.default ~= nil then
            val = args.default
        else
            error(string.format('value "%s" of type "%s" is not an integer', tostring(value), t))
        end
    end
    
    if args.min ~= nil and val < args.min then
        error(string.format('"%i" is too small. Minimum: "%i"', val, args.min))
    end
    
    if args.max ~= nil and val > args.max then
        error(string.format('"%i" is too large. Maximum: "%i"', val, args.max))
    end
    
    return val
end

-- ----------------------------------------------------------------------------
-- util.html
-- ----------------------------------------------------------------------------

util.html = {}
function util.html.abbr(abbr, text, class)
    tag = mw.html.create('abbr')
    tag
        :attr('title', text or '')
        :attr('class', class or '')
        :wikitext(abbr or ' ')
        :done()
        
    return tostring(tag)
end

-- ----------------------------------------------------------------------------
-- util.misc
-- ----------------------------------------------------------------------------

util.misc = {}
function util.misc.is_frame(frame)
    -- the type of the frame is a table containing the functions, so check whether some of these exist
    -- should be enough to avoid collisions.
    return not(frame == nil or type(frame) ~= 'table' or (frame.argumentPairs == nil and frame.callParserFunction == nil))
end

function util.misc.get_frame(frame)
    if util.misc.is_frame(frame) then
        return frame
    end
    return mw.getCurrentFrame()
end

function util.misc.add_category(categories, args)
    -- categories: table of categories
    -- args: table of extra arguments
    --  namespace: id of namespace to validate against
    --  ingore_blacklist: set to non-nil to ingore the blacklist
    if type(categories) == 'string' then
        categories = {categories}
    end
    
    if args == nil then
        args = {}
    end
    
    
    local title = mw.title.getCurrentTitle()
    local sub_blacklist = {
        doc = true,
        sandbox = true,
        sandbox2 = true,
        testcases = true,
    }
    
    if args.namespace ~= nil and title.namespace ~= args.namespace then
        return ''
    end
    
    if args.ingore_blacklist == nil and sub_blacklist[title.subpageText] then
        return ''
    end
   
    local cats = {}
    
    for i, cat in ipairs(categories) do
        cats[i] = string.format('[[Category:%s]]', cat)
    end
    return table.concat(cats)
end

-- ----------------------------------------------------------------------------
-- util.smw
-- ----------------------------------------------------------------------------

util.smw = {}

util.smw.data = {}
util.smw.data.rejected_namespaces = xtable:new({'User'})

function util.smw.query(query, frame)
    -- Executes a semantic media wiki #ask query and returns the result as an
    -- array containing each row as table.
    --
    -- query: table of query arguments to pass
    -- frame: current frame object
    local defaults = {
        format='template',
        template='SMW generic list',
        sep=',',
        link='none',
        ['named args']='yes',
        searchlabel='',
        userparam='sep=;, seprow=\n',
    }
    
    for k, v in pairs(defaults) do
        if query[k] == nil then
            query[k] = v
        end
    end
    
    local result = frame:callParserFunction('#ask:', query)
    
    -- "<span class=\"smw-highlighter\" data-type=\"4\" data-state=\"inline\" data-title=\"Error\"><span class=\"smwtticon warning\"></span><div class=\"smwttcontent\">Some subquery has no valid condition.</div></span>"
    if mw.ustring.find(result, 'data%-title="Error"') ~= nil then
        error(result)
    end
    
    result = mw.ustring.gsub( result, '%[%[SMW::o[fn]+%]%]', '')
    
    local out = {}
    
    for s in mw.text.gsplit(result, '\n') do
        if string.len(s) > 0 then
            out[#out+1] = util.string.split_args(s, {sep=';'})
        end
    end
    
    return out
end

function util.smw.safeguard(args)
    -- Used for safeguarding data entry so it doesn't get added on user space stuff
    --
    -- Args:
    --  smw_ingore_safeguard - ingore safeguard and return true
    if args == nil then
        args = {}
    end

    if args.smw_ingore_safeguard then
        return true
    end
    
    local namespace = mw.site.namespaces[mw.title.getCurrentTitle().namespace].name
    if util.smw.data.rejected_namespaces:contains(namespace) then
        return false
    end
    
    return true
end


-- ----------------------------------------------------------------------------
-- util.string
-- ----------------------------------------------------------------------------

util.string = {}
function util.string.split_args(str, args)
    -- Splits arguments string into a table
    --
    -- str: String of arguments to split
    -- args: table of extra arguments
    --  sep: separator to use (default: ,)
    local out = {}
    
    if args == nil then
        args = {}
    end
    
    if str ~= nil then
        local row
        for str in mw.text.gsplit(str, args.sep or ',') do
            row = mw.text.split(str, '=')
            if #row == 1 then
                out[#out+1] = row[1] 
            elseif #row == 2 then
                out[row[1]] = row[2]
            else
                error(string.format('Number of arguments near = is too large (%s).', #row))
            end
        end
    end
    
    return out
end

-- ----------------------------------------------------------------------------
-- util.table
-- ----------------------------------------------------------------------------

util.table = {}
function util.table.find_in_nested_array(args) 
    -- Iterates thoguh the given nested array and finds the given value
    -- 
    -- ex.   
    -- data = {
    -- {a=5}, {a=6}}
    -- find_nested_array{arg=6, tbl=data, key='a'} -> 6
    -- find_nested_array(arg=10, tbl=data, key='a'} -> nil
    -- -> returns "6"
    
    --
    -- args: Table containing:
    --  value: value of the argument
    --  tbl: table of valid options
    --  key: key or table of key of in tbl
    --  rtrkey: if key is table, return this key instead of the value instead
    --  rtrvalue: default: true
    
    local rtr
    
    if type(args.key) == 'table' then
        for _, item in ipairs(args.tbl) do
            for _, k in ipairs(args.key) do
                if item[k] == args.value then
                    rtr = item
                    break
                end
            end
        end
    elseif args.key == nil then
        for _, item in ipairs(args.tbl) do
            if item == args.value then
                rtr = item
                break
            end
        end
    else
        for _, item in ipairs(args.tbl) do
            if item[args.key] == args.value then
                rtr = item
                break
            end
        end
    end
    
    if rtr == nil then
        return rtr
    end

    if args.rtrkey ~= nil then 
        return rtr[args.rtrkey]
    elseif args.rtrvalue or args.rtrvalue == nil then
        return args.value
    else
        return rtr
    end
end

-- ----------------------------------------------------------------------------

return util