[dismiss]
The wiki is currently a work in progress. If you'd like to help out, please check the Community Portal and our getting started guide. Also, check out our sister project on poewiki.net.
Module:Util: Difference between revisions
Jump to navigation
Jump to search
>OmegaK2 (added tooltip function) |
>TheFrz mNo edit summary |
||
Line 13: | Line 13: | ||
function util.cast.boolean(value) | function util.cast.boolean(value) | ||
-- Takes an abitary value and casts it to a bool value | -- Takes an abitary value and casts it to a bool value | ||
-- | -- | ||
-- for strings false will be according to util.cast.bool_false | -- for strings false will be according to util.cast.bool_false | ||
local t = type(value) | local t = type(value) | ||
Line 34: | Line 34: | ||
error(string.format('value "%s" of type "%s" is not a boolean', value, t)) | error(string.format('value "%s" of type "%s" is not a boolean', value, t)) | ||
end | end | ||
end | end | ||
Line 47: | Line 47: | ||
args = {} | args = {} | ||
end | end | ||
local t = type(value) | local t = type(value) | ||
local val | local val | ||
if t == 'nil' then | if t == 'nil' then | ||
val = nil | val = nil | ||
Line 64: | Line 64: | ||
val = tonumber(value) | val = tonumber(value) | ||
end | end | ||
if val == nil then | if val == nil then | ||
if args.default ~= nil then | if args.default ~= nil then | ||
Line 72: | Line 72: | ||
end | end | ||
end | end | ||
if args.min ~= nil and val < args.min then | if args.min ~= nil and val < args.min then | ||
error(string.format('"%i" is too small. Minimum: "%i"', val, args.min)) | error(string.format('"%i" is too small. Minimum: "%i"', val, args.min)) | ||
end | end | ||
if args.max ~= nil and val > args.max then | if args.max ~= nil and val > args.max then | ||
error(string.format('"%i" is too large. Maximum: "%i"', val, args.max)) | error(string.format('"%i" is too large. Maximum: "%i"', val, args.max)) | ||
end | end | ||
return val | return val | ||
end | end | ||
Line 87: | Line 87: | ||
-- Takes a string value and returns as version number | -- Takes a string value and returns as version number | ||
-- If the version number is invalid an error is raised | -- If the version number is invalid an error is raised | ||
-- | -- | ||
-- args: | -- args: | ||
-- return_type: defaults to "table" | -- return_type: defaults to "table" | ||
-- table - Returns the version number broken down into sub versions as a table | -- table - Returns the version number broken down into sub versions as a table | ||
-- string - Returns the version number as string | -- string - Returns the version number as string | ||
-- | -- | ||
if args == nil then | if args == nil then | ||
args = {} | args = {} | ||
end | end | ||
local result | local result | ||
if args.return_type == 'table' or args.return_type == nil then | if args.return_type == 'table' or args.return_type == nil then | ||
result = util.string.split(value, '%.') | result = util.string.split(value, '%.') | ||
if #result ~= 3 then | if #result ~= 3 then | ||
error(string.format('Malformed version string "%s"', value)) | error(string.format('Malformed version string "%s"', value)) | ||
end | end | ||
result[4] = string.match(result[3], '%a+') | result[4] = string.match(result[3], '%a+') | ||
result[3] = string.match(result[3], '%d+') | result[3] = string.match(result[3], '%d+') | ||
for i=1,3 do | for i=1,3 do | ||
local v = tonumber(result[i]) | local v = tonumber(result[i]) | ||
Line 118: | Line 118: | ||
result = string.match(value, '%d+%.%d+%.%d+%a*') | result = string.match(value, '%d+%.%d+%.%d+%a*') | ||
end | end | ||
if result == nil then | if result == nil then | ||
error(string.format('"%s" is not a recognized version number', value)) | error(string.format('"%s" is not a recognized version number', value)) | ||
end | end | ||
return result | return result | ||
end | end | ||
Line 155: | Line 155: | ||
args.subobject_prefix = args.subobject_prefix or '' | args.subobject_prefix = args.subobject_prefix or '' | ||
args.properties = args.properties or {} | args.properties = args.properties or {} | ||
local i = 0 | local i = 0 | ||
local stats = {} | local stats = {} | ||
Line 166: | Line 166: | ||
value = string.format('%sstat%s_value', args.prefix, i), | value = string.format('%sstat%s_value', args.prefix, i), | ||
} | } | ||
local value = {} | local value = {} | ||
for key, args_key in pairs(id) do | for key, args_key in pairs(id) do | ||
value[key] = argtbl[args_key] | value[key] = argtbl[args_key] | ||
end | end | ||
if value.id ~= nil and ((value.min ~= nil and value.max ~= nil and value.value == nil) or (value.min == nil and value.max == nil and value.value ~= nil)) then | if value.id ~= nil and ((value.min ~= nil and value.max ~= nil and value.value == nil) or (value.min == nil and value.max == nil and value.value ~= nil)) then | ||
local properties = {} | local properties = {} | ||
Line 183: | Line 183: | ||
value.max = util.cast.number(value.max) | value.max = util.cast.number(value.max) | ||
argtbl[id.max] = value.max | argtbl[id.max] = value.max | ||
-- Also set average value | -- Also set average value | ||
value.avg = (value.min + value.max)/2 | value.avg = (value.min + value.max)/2 | ||
Line 190: | Line 190: | ||
argtbl[string.format('%sstat%s', args.prefix, i)] = value | argtbl[string.format('%sstat%s', args.prefix, i)] = value | ||
stats[#stats+1] = value | stats[#stats+1] = value | ||
if args.frame ~= nil then | if args.frame ~= nil then | ||
local properties = {} | local properties = {} | ||
Line 196: | Line 196: | ||
properties[property] = value | properties[property] = value | ||
end | end | ||
for key, property in pairs(util.args.stat_properties) do | for key, property in pairs(util.args.stat_properties) do | ||
properties[string.format(property, args.property_prefix)] = value[key] | properties[string.format(property, args.property_prefix)] = value[key] | ||
end | end | ||
util.smw.subobject(args.frame, string.format('%sstat%s_%s', args.subobject_prefix, i, value.id), properties) | util.smw.subobject(args.frame, string.format('%sstat%s_%s', args.subobject_prefix, i, value.id), properties) | ||
end | end | ||
Line 210: | Line 210: | ||
end | end | ||
until value == nil | until value == nil | ||
argtbl[string.format('%sstats', args.prefix)] = stats | argtbl[string.format('%sstats', args.prefix)] = stats | ||
end | end | ||
Line 232: | Line 232: | ||
}, | }, | ||
} | } | ||
local version_ids = {} | local version_ids = {} | ||
local version_keys = {} | local version_keys = {} | ||
for key, data in pairs(args.variables) do | for key, data in pairs(args.variables) do | ||
local full_key = string.format('%s_version', key) | local full_key = string.format('%s_version', key) | ||
Line 248: | Line 248: | ||
end | end | ||
end | end | ||
-- no need to do a query if nothing was fetched | -- no need to do a query if nothing was fetched | ||
if #version_ids > 0 then | if #version_ids > 0 then | ||
Line 254: | Line 254: | ||
error('Properties were set, but frame was not') | error('Properties were set, but frame was not') | ||
end | end | ||
local query = {} | local query = {} | ||
query[#query+1] = string.format('[[Is version::%s]]', table.concat(version_ids, '||')) | query[#query+1] = string.format('[[Is version::%s]]', table.concat(version_ids, '||')) | ||
query[#query+1] = '?Has release date#' | query[#query+1] = '?Has release date#' | ||
query[#query+1] = '?Is version' | query[#query+1] = '?Is version' | ||
local results = util.smw.query(query, args.frame) | local results = util.smw.query(query, args.frame) | ||
if #results ~= #version_ids then | if #results ~= #version_ids then | ||
error(string.format('The number of results (%s) does not match the number version arguments (%s)', #results, #version_ids)) | error(string.format('The number of results (%s) does not match the number version arguments (%s)', #results, #version_ids)) | ||
end | end | ||
for _, row in ipairs(results) do | for _, row in ipairs(results) do | ||
local key = version_keys[row['Is version']] | local key = version_keys[row['Is version']] | ||
Line 271: | Line 271: | ||
end | end | ||
end | end | ||
if args.set_properties ~= nil then | if args.set_properties ~= nil then | ||
local properties = {} | local properties = {} | ||
Line 280: | Line 280: | ||
end | end | ||
end | end | ||
util.smw.set(args.frame, properties) | util.smw.set(args.frame, properties) | ||
end | end | ||
Line 302: | Line 302: | ||
args = {} | args = {} | ||
end | end | ||
local err = mw.html.create('span') | local err = mw.html.create('span') | ||
err | err | ||
Line 308: | Line 308: | ||
:wikitext('Module Error: ' .. (args.msg or '')) | :wikitext('Module Error: ' .. (args.msg or '')) | ||
:done() | :done() | ||
return tostring(err) | return tostring(err) | ||
end | end | ||
Line 387: | Line 387: | ||
categories = {categories} | categories = {categories} | ||
end | end | ||
if args == nil then | if args == nil then | ||
args = {} | args = {} | ||
end | end | ||
local title = mw.title.getCurrentTitle() | local title = mw.title.getCurrentTitle() | ||
local sub_blacklist = args.sub_page_blacklist or util.misc.category_blacklist.sub_pages | local sub_blacklist = args.sub_page_blacklist or util.misc.category_blacklist.sub_pages | ||
local ns_blacklist = args.namespace_blacklist or util.misc.category_blacklist.namespaces | local ns_blacklist = args.namespace_blacklist or util.misc.category_blacklist.namespaces | ||
if args.namespace ~= nil and title.namespace ~= args.namespace then | if args.namespace ~= nil and title.namespace ~= args.namespace then | ||
return '' | return '' | ||
end | end | ||
if args.ingore_blacklist == nil and (sub_blacklist[title.subpageText] or ns_blacklist[title.subjectNsText]) then | if args.ingore_blacklist == nil and (sub_blacklist[title.subpageText] or ns_blacklist[title.subjectNsText]) then | ||
return '' | return '' | ||
end | end | ||
local cats = {} | local cats = {} | ||
for i, cat in ipairs(categories) do | for i, cat in ipairs(categories) do | ||
cats[i] = string.format('[[Category:%s]]', cat) | cats[i] = string.format('[[Category:%s]]', cat) | ||
Line 414: | Line 414: | ||
function util.misc.raise_error_or_return(args) | function util.misc.raise_error_or_return(args) | ||
-- | -- | ||
-- Arguments: | -- Arguments: | ||
-- args: table of arguments to this function (must be set) | -- args: table of arguments to this function (must be set) | ||
Line 460: | Line 460: | ||
-- frame : frame object | -- frame : frame object | ||
-- parser_function: the whole parser function string | -- parser_function: the whole parser function string | ||
-- args : table of arguments | -- args : table of arguments | ||
for k, v in pairs(args) do | for k, v in pairs(args) do | ||
if type(v) == 'table' then | if type(v) == 'table' then | ||
Line 488: | Line 488: | ||
-- query: table of query arguments to pass | -- query: table of query arguments to pass | ||
-- frame: current frame object | -- frame: current frame object | ||
-- the characters here for sep/header/propsep are control characters; I'm farily certain they should not appear in regular text. | -- the characters here for sep/header/propsep are control characters; I'm farily certain they should not appear in regular text. | ||
query.sep = '�' | query.sep = '�' | ||
Line 495: | Line 495: | ||
query.format = 'array' | query.format = 'array' | ||
query.headers = 'plain' | query.headers = 'plain' | ||
local result = frame:callParserFunction('#ask', query) | 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>" | -- "<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 | if mw.ustring.find(result, 'data%-title="Error"') ~= nil then | ||
Line 504: | Line 504: | ||
local out = {} | local out = {} | ||
for row_string in string.gmatch(result, '[^�]+') do | for row_string in string.gmatch(result, '[^�]+') do | ||
local row = {} | local row = {} | ||
Line 510: | Line 510: | ||
local kv = util.string.split(str, query.headersep) | local kv = util.string.split(str, query.headersep) | ||
if #kv == 1 then | if #kv == 1 then | ||
row[#row+1] = kv[1] | row[#row+1] = kv[1] | ||
elseif #kv == 2 then | elseif #kv == 2 then | ||
row[kv[1]] = kv[2] | row[kv[1]] = kv[2] | ||
Line 517: | Line 517: | ||
out[#out+1] = row | out[#out+1] = row | ||
end | end | ||
return out | return out | ||
end | end | ||
Line 533: | Line 533: | ||
return true | return true | ||
end | end | ||
local namespace = mw.site.namespaces[mw.title.getCurrentTitle().namespace].name | local namespace = mw.site.namespaces[mw.title.getCurrentTitle().namespace].name | ||
if util.smw.data.rejected_namespaces:contains(namespace) then | if util.smw.data.rejected_namespaces:contains(namespace) then | ||
return false | return false | ||
end | end | ||
return true | return true | ||
end | end | ||
Line 553: | Line 553: | ||
-- str: string to split | -- str: string to split | ||
-- pattern: pattern to use for splitting | -- pattern: pattern to use for splitting | ||
out = {} | local out = {} | ||
local i = 1 | local i = 1 | ||
local split_start, split_end = string.find(str, pattern, i) | local split_start, split_end = string.find(str, pattern, i) | ||
Line 573: | Line 573: | ||
-- kvsep: separator to use for key value pairs (default: =) | -- kvsep: separator to use for key value pairs (default: =) | ||
local out = {} | local out = {} | ||
if args == nil then | if args == nil then | ||
args = {} | args = {} | ||
end | end | ||
args.sep = args.sep or ',' | args.sep = args.sep or ',' | ||
args.kvsep = args.kvsep or '=' | args.kvsep = args.kvsep or '=' | ||
if str ~= nil then | if str ~= nil then | ||
local row | local row | ||
Line 586: | Line 586: | ||
row = util.string.split(str, args.kvsep) | row = util.string.split(str, args.kvsep) | ||
if #row == 1 then | if #row == 1 then | ||
out[#out+1] = row[1] | out[#out+1] = row[1] | ||
elseif #row == 2 then | elseif #row == 2 then | ||
out[row[1]] = row[2] | out[row[1]] = row[2] | ||
Line 594: | Line 594: | ||
end | end | ||
end | end | ||
return out | return out | ||
end | end | ||
Line 603: | Line 603: | ||
util.table = {} | util.table = {} | ||
function util.table.length(tbl) | |||
-- Get length of the metatable | |||
local length = 0 | |||
for _ in ipairs(tbl) do | |||
length = length + 1 | |||
end | |||
return length | |||
end | |||
function util.table.has_all_value(tbl, keys, value) | function util.table.has_all_value(tbl, keys, value) | ||
-- Whether all the table values with the specified keys are the specified value | -- Whether all the table values with the specified keys are the specified value | ||
Line 623: | Line 632: | ||
end | end | ||
function util.table.find_in_nested_array(args) | function util.table.find_in_nested_array(args) | ||
-- Iterates thoguh the given nested array and finds the given value | -- Iterates thoguh the given nested array and finds the given value | ||
-- | -- | ||
-- ex. | -- ex. | ||
-- data = { | -- data = { | ||
-- {a=5}, {a=6}} | -- {a=5}, {a=6}} | ||
Line 632: | Line 641: | ||
-- find_nested_array(arg=10, tbl=data, key='a'} -> nil | -- find_nested_array(arg=10, tbl=data, key='a'} -> nil | ||
-- -> returns "6" | -- -> returns "6" | ||
-- | -- | ||
-- args: Table containing: | -- args: Table containing: | ||
Line 640: | Line 649: | ||
-- rtrkey: if key is table, return this key instead of the value instead | -- rtrkey: if key is table, return this key instead of the value instead | ||
-- rtrvalue: default: true | -- rtrvalue: default: true | ||
local rtr | local rtr | ||
if type(args.key) == 'table' then | if type(args.key) == 'table' then | ||
for _, item in ipairs(args.tbl) do | for _, item in ipairs(args.tbl) do | ||
Line 667: | Line 676: | ||
end | end | ||
end | end | ||
if rtr == nil then | if rtr == nil then | ||
return rtr | return rtr | ||
end | end | ||
if args.rtrkey ~= nil then | if args.rtrkey ~= nil then | ||
return rtr[args.rtrkey] | return rtr[args.rtrkey] | ||
elseif args.rtrvalue or args.rtrvalue == nil then | elseif args.rtrvalue or args.rtrvalue == nil then |
Revision as of 17:26, 3 January 2017

This is a meta module.
This module is meant to be used only by other modules. It should not be invoked in wikitext.
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()
.
The above documentation is transcluded from Module:Util/doc.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
Editors can experiment in this module's sandbox and testcases pages.
Subpages of this module.
-- 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
function util.cast.version(value, args)
-- Takes a string value and returns as version number
-- If the version number is invalid an error is raised
--
-- args:
-- return_type: defaults to "table"
-- table - Returns the version number broken down into sub versions as a table
-- string - Returns the version number as string
--
if args == nil then
args = {}
end
local result
if args.return_type == 'table' or args.return_type == nil then
result = util.string.split(value, '%.')
if #result ~= 3 then
error(string.format('Malformed version string "%s"', value))
end
result[4] = string.match(result[3], '%a+')
result[3] = string.match(result[3], '%d+')
for i=1,3 do
local v = tonumber(result[i])
if v == nil then
error(string.format('"%s" has an non-number component', value))
end
result[i] = v
end
elseif args.return_type == 'string' then
result = string.match(value, '%d+%.%d+%.%d+%a*')
end
if result == nil then
error(string.format('"%s" is not a recognized version number', value))
end
return result
end
-- ----------------------------------------------------------------------------
-- util.args
-- ----------------------------------------------------------------------------
util.args = {}
util.args.stat_properties = {
id = 'Has %sstat id',
min = 'Has minimum %sstat value',
max = 'Has maximum %sstat value',
avg = 'Has average %sstat value',
value = 'Has %sstat value',
}
function util.args.stats(argtbl, args)
-- in any prefix spaces should be included
--
-- argtbl: argument table to work with
-- args:
-- prefix: prefix if any
-- frame: frame used to set subobjects; if not set dont set properties
-- property_prefix: property prefix if any
-- subobject_prefix: subobject prefix if any
-- properties: table of properties to add if any
args = args or {}
args.prefix = args.prefix or ''
args.property_prefix = args.property_prefix or ''
args.subobject_prefix = args.subobject_prefix or ''
args.properties = args.properties or {}
local i = 0
local stats = {}
repeat
i = i + 1
local id = {
id = string.format('%sstat%s_id', args.prefix, i),
min = string.format('%sstat%s_min', args.prefix, i),
max = string.format('%sstat%s_max', args.prefix, i),
value = string.format('%sstat%s_value', args.prefix, i),
}
local value = {}
for key, args_key in pairs(id) do
value[key] = argtbl[args_key]
end
if value.id ~= nil and ((value.min ~= nil and value.max ~= nil and value.value == nil) or (value.min == nil and value.max == nil and value.value ~= nil)) then
local properties = {}
if value.value then
value.value = util.cast.number(value.value)
argtbl[id.value] = value.value
else
value.min = util.cast.number(value.min)
argtbl[id.min] = value.min
value.max = util.cast.number(value.max)
argtbl[id.max] = value.max
-- Also set average value
value.avg = (value.min + value.max)/2
argtbl[string.format('%sstat%s_avg', args.prefix, i)] = value.avg
end
argtbl[string.format('%sstat%s', args.prefix, i)] = value
stats[#stats+1] = value
if args.frame ~= nil then
local properties = {}
for property, value in pairs(args.properties) do
properties[property] = value
end
for key, property in pairs(util.args.stat_properties) do
properties[string.format(property, args.property_prefix)] = value[key]
end
util.smw.subobject(args.frame, string.format('%sstat%s_%s', args.subobject_prefix, i, value.id), properties)
end
elseif util.table.has_all_value(value, {'id', 'min', 'max', 'value'}, nil) then
value = nil
-- all other cases should be improperly set value
else
error(string.format('%sstat%s is improperly set; id and either value or min/max must be specified.', args.prefix, i))
end
until value == nil
argtbl[string.format('%sstats', args.prefix)] = stats
end
function util.args.version (argtbl, args)
-- in any prefix spaces should be included
--
-- argtbl: argument table to work with
-- args:
-- frame: frame for queries
-- set_properties: if defined, set properties on the page
-- variables: table of prefixes of
-- property: property; if not set skip fetching and setting release date
args = args or {}
args.variables = args.variables or {
release = {
property = 'Has release',
},
removal = {
property = 'Has removal',
},
}
local version_ids = {}
local version_keys = {}
for key, data in pairs(args.variables) do
local full_key = string.format('%s_version', key)
if argtbl[full_key] ~= nil then
local value = util.cast.version(argtbl[full_key], {return_type = 'string'})
argtbl[full_key] = value
data.value = value
if data.property ~= nil then
version_ids[#version_ids+1] = value
version_keys[value] = key
end
end
end
-- no need to do a query if nothing was fetched
if #version_ids > 0 then
if args.frame == nil then
error('Properties were set, but frame was not')
end
local query = {}
query[#query+1] = string.format('[[Is version::%s]]', table.concat(version_ids, '||'))
query[#query+1] = '?Has release date#'
query[#query+1] = '?Is version'
local results = util.smw.query(query, args.frame)
if #results ~= #version_ids then
error(string.format('The number of results (%s) does not match the number version arguments (%s)', #results, #version_ids))
end
for _, row in ipairs(results) do
local key = version_keys[row['Is version']]
argtbl[string.format('%s_date', key)] = row['Has release date']
end
end
if args.set_properties ~= nil then
local properties = {}
for key, data in pairs(args.variables) do
if data.property ~= nil then
properties[string.format('%s version', data.property)] = argtbl[string.format('%s_version', key)]
properties[string.format('%s date', data.property)] = argtbl[string.format('%s_date', key)]
end
end
util.smw.set(args.frame, properties)
end
end
-- ----------------------------------------------------------------------------
-- util.html
-- ----------------------------------------------------------------------------
util.html = {}
function util.html.abbr(abbr, text, class)
return string.format('<abbr title="%s" class="%s">%s</abbr>', text or '', class or '', abbr or '')
end
function util.html.error(args)
-- Create an error message box
--
-- Args:
-- msg - message
if args == nil then
args = {}
end
local err = mw.html.create('span')
err
:attr('class', 'module-error')
:wikitext('Module Error: ' .. (args.msg or ''))
:done()
return tostring(err)
end
function util.html.poe_color(label, text)
if text == nil or text == '' then
return nil
end
return tostring(mw.html.create('em')
:attr('class', 'tc -' .. label)
:wikitext(text))
end
function util.html.tooltip(abbr, text, class)
return string.format('<span class="tooltip-activator %s">%s<span class="tooltip-content">%s</span></span>', class or '', abbr or '', text or '')
end
util.html.td = {}
function util.html.td.na(args)
--
-- Args:
-- as_tag
args = args or {}
-- N/A table row, requires mw.html.create instance to be passed
local td = mw.html.create('td')
td
:attr('class', 'table-na')
:wikitext('N/A')
:done()
if args.as_tag then
return td
else
return tostring(td)
end
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
util.misc.category_blacklist = {}
util.misc.category_blacklist.sub_pages = {
doc = true,
sandbox = true,
sandbox2 = true,
testcases = true,
}
util.misc.category_blacklist.namespaces = {
Template = true,
Template_talk = true,
Module = true,
Module_talk = true,
}
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
-- sub_page_blacklist: blacklist of subpages to use (if empty, use default)
-- namespace_blacklist: blacklist of namespaces to use (if empty, use default)
if type(categories) == 'string' then
categories = {categories}
end
if args == nil then
args = {}
end
local title = mw.title.getCurrentTitle()
local sub_blacklist = args.sub_page_blacklist or util.misc.category_blacklist.sub_pages
local ns_blacklist = args.namespace_blacklist or util.misc.category_blacklist.namespaces
if args.namespace ~= nil and title.namespace ~= args.namespace then
return ''
end
if args.ingore_blacklist == nil and (sub_blacklist[title.subpageText] or ns_blacklist[title.subjectNsText]) 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
function util.misc.raise_error_or_return(args)
--
-- Arguments:
-- args: table of arguments to this function (must be set)
-- One required:
-- raise_required: Don't raise errors and return html errors instead unless raisae is set in arguments
-- no_raise_required: Don't return html errors and raise errors insetad unless no_raise is set in arguments
--
-- Optional:
-- msg: error message to raise or return, default: nil
-- args: argument directory to validate against (e.x. template args), default: {}
args.args = args.args or {}
args.msg = args.msg or ''
if args.raise_required ~= nil then
if args.args.raise ~= nil then
error(args.msg)
else
return util.html.error{msg=args.msg}
end
elseif args.no_raise_required ~= nil then
if args.args.no_raise ~= nil then
return util.html.error{msg=args.msg}
else
error(args.msg)
end
else
error('Invalid usage of raise_error_or_return.')
end
end
-- ----------------------------------------------------------------------------
-- util.smw
-- ----------------------------------------------------------------------------
util.smw = {}
util.smw.data = {}
util.smw.data.rejected_namespaces = xtable:new({'User'})
function util.smw._parser_function(frame, parser_function, args)
-- Executes a semantic parser functions and sets the arguments args
--
-- This function is a helper for handling tables since +sep= parameter
-- appears to be broken.
--
-- frame : frame object
-- parser_function: the whole parser function string
-- args : table of arguments
for k, v in pairs(args) do
if type(v) == 'table' then
for _, value in ipairs(v) do
frame:callParserFunction(parser_function, {[k] = value})
end
args[k] = nil
elseif type(v) == 'boolean' then
args[k] = tostring(v)
end
end
frame:callParserFunction(parser_function, args)
end
function util.smw.set(frame, args)
util.smw._parser_function(frame, '#set:', args)
end
function util.smw.subobject(frame, id, args)
util.smw._parser_function(frame, '#subobject:' .. id, args)
end
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
-- the characters here for sep/header/propsep are control characters; I'm farily certain they should not appear in regular text.
query.sep = '�'
query.propsep = '<PROP>'
query.headersep = '<HEAD>'
query.format = 'array'
query.headers = 'plain'
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(mw.ustring.sub(result, mw.ustring.find(result, '<span class="smw-highlighter"', 1, true), -1))
end
local out = {}
for row_string in string.gmatch(result, '[^�]+') do
local row = {}
for _, str in ipairs(util.string.split(row_string, query.propsep)) do
local kv = util.string.split(str, query.headersep)
if #kv == 1 then
row[#row+1] = kv[1]
elseif #kv == 2 then
row[kv[1]] = kv[2]
end
end
out[#out+1] = row
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(str, pattern)
-- Splits string into a table
--
-- str: string to split
-- pattern: pattern to use for splitting
local out = {}
local i = 1
local split_start, split_end = string.find(str, pattern, i)
while split_start do
out[#out+1] = string.sub(str, i, split_start-1)
i = split_end+1
split_start, split_end = string.find(str, pattern, i)
end
out[#out+1] = string.sub(str, i)
return out
end
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: ,)
-- kvsep: separator to use for key value pairs (default: =)
local out = {}
if args == nil then
args = {}
end
args.sep = args.sep or ','
args.kvsep = args.kvsep or '='
if str ~= nil then
local row
for _, str in ipairs(util.string.split(str, args.sep)) do
row = util.string.split(str, args.kvsep)
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.length(tbl)
-- Get length of the metatable
local length = 0
for _ in ipairs(tbl) do
length = length + 1
end
return length
end
function util.table.has_all_value(tbl, keys, value)
-- Whether all the table values with the specified keys are the specified value
for _, k in ipairs(keys or {}) do
if tbl[k] ~= value then
return false
end
end
return true
end
function util.table.has_one_value(tbl, keys, value)
-- Whether one of table values with the specified keys is the specified value
for _, k in ipairs(keys or {}) do
if tbl[k] == value then
return true
end
end
return false
end
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