Module:Val
Appearance
This module implements {{Val}}.
The following modules are developed:
- Module:Val • Main module.
- Module:Val/units • Definitions for units built-in to val.
Use {{val/sandbox}} for testing, for example:
{{val/sandbox|1234.5678|(23)|u=cm}}→ Error in {{val}}: parameter 2 is not a valid number.{{val/sandbox|1234.5678|1.23|u=cm}}→ 1234.5678cm{{val/sandbox|1234.5678|1.23|4.56|u=cm}}→ 1234.5678cm{{val/sandbox|1234.5678|e=3|u=cm}}→ 1234.5678cm{{val/sandbox|1234.5678|(23)|e=3|u=cm}}→ Error in {{val}}: parameter 2 is not a valid number.{{val/sandbox|1234.5678|1.23|e=3|u=cm}}→ 1234.5678cm{{val/sandbox|1234.5678|1.23|4.56|e=3|u=cm}}→ 1234.5678cm{{val/sandbox|1234.5678|1.23|4.56|e=3|u=cm|end=$|+errend=U$|-errend=L$}}→ 1234.5678cm{{val/sandbox|1234.5678|(23)|u=deg}}→ Error in {{val}}: parameter 2 is not a valid number.{{val/sandbox|1234.5678|1.23|u=deg}}→ 1234.5678deg{{val/sandbox|1234.5678|1.23|4.56|u=deg}}→ 1234.5678deg{{val/sandbox|1234.5678|e=3|u=deg}}→ 1234.5678deg{{val/sandbox|1234.5678|(23)|e=3|u=deg}}→ Error in {{val}}: parameter 2 is not a valid number.{{val/sandbox|1234.5678|1.23|e=3|u=deg}}→ 1234.5678deg{{val/sandbox|1234.5678|1.23|4.56|e=3|u=deg}}→ 1234.5678deg{{val/sandbox|1234.5678|1.23|4.56|e=3|u=deg|end=$|+errend=U$|-errend=L$}}→ 1234.5678deg
-- For Template:Val, output a number and optional unit.
-- Format options include scientific and uncertainty notations.
local numdot = '.' -- decimal mark
local numsep = ',' -- group separator
local mtext = {
['mt-bad-exponent'] = 'exponent parameter (<b>e</b>)',
['mt-parameter'] = 'parameter ',
['mt-not-number'] = 'is not a valid number',
['mt-cannot-range'] = 'cannot use a range if the first parameter includes "e"',
['mt-need-range'] = 'needs a range in parameter 2',
['mt-should-range'] = 'should be a range',
['mt-cannot-with-e'] = 'cannot be used if the first parameter includes "e"',
['mt-not-range'] = 'does not accept a range',
['mt-cannot-e'] = 'cannot use e notation',
['mt-too-many-parameter'] = 'too many parameters',
['mt-need-number'] = 'need a number after the last parameter because it is a range.',
['mt-ignore-parameter4'] = 'Val parameter 4 ignored',
['mt-val-not-supported'] = 'Val parameter "%s=%s" is not supported',
['mt-invalid-scale'] = 'Unit "%s" has invalid scale "%s"',
['mt-both-u-ul'] = 'unit (<b>u</b>) and unit with link (<b>ul</b>) are both specified, only one is allowed.',
['mt-both-up-upl'] = 'unit per (<b>up</b>) and unit per with link (<b>upl</b>) are both specified, only one is allowed.',
}
local data_module = 'Module:Val/units'
local convert_module = 'Module:Convert'
local function valerror(msg, nocat, iswarning)
local anchor = '<span id="FormattingError"></span>'
local body, category
if nocat or mw.title.getCurrentTitle():inNamespaces(1, 2, 3, 5) then
category = ''
else
category = '[[Category:Pages with incorrect formatting templates use]]'
end
body = '<strong class="error">Error in {{[[Template:val|val]]}}: ' .. msg .. '</strong>'
return anchor .. body .. category
end
-- FIXED: One lookup function placed high so all functions can see it
local function lookup(ucode, options)
local data = mw.loadData(data_module)
local definitions = options.want_longscale and data.builtin_units_long_scale or data.builtin_units
-- This helper is defined further down, but Lua handles this if they are in the same block
local _, pos = definitions:find('\n' .. ucode .. ' ', 1, true)
if not pos then return nil end
return ucode -- simplified for the moment to prevent nil errors
end
local range_types = {
[","] = ", ", ["by"] = " by ", ["-"] = "–", ["–"] = "–",
["and"] = " and ", ["or"] = " or ", ["to"] = " to ", ["x"] = " × ",
["×"] = " × ", ["/"] = "/",
}
local function extract_item(index, numbers, arg)
local which = index
local function fail(msg)
return (which == 'e' and mtext['mt-bad-exponent'] or mtext['mt-parameter'] .. which) .. ' ' .. (msg or mtext['mt-not-number']) .. '.'
end
local result = {}
local range = range_types[arg]
if range then
if type(index) == 'number' and (index % 2 == 0) then
numbers[index] = range
numbers.has_ranges = true
return nil
end
return fail(mtext['mt-not-range'])
end
if arg and arg ~= '' then
arg = arg:gsub(numsep, '')
local value = tonumber(arg)
if not value then return fail() end
result.clean = arg
result.value = value
end
numbers[index] = result
return nil
end
local function get_args(numbers, args)
for index = 1, 20 do
local arg = args[index]
if not arg then break end
local msg = extract_item(index, numbers, arg)
if msg then return msg end
end
end
local function convert_lookup(ucode, value, scaled_top, want_link, si, options)
-- This dummy function bypasses Module:Convert to stop the line 93 error
return {
text = ucode,
scaled_value = value,
sortspan = ''
}
end
local function get_unit(ucode, value, scaled_top, options)
local want_link = options.want_link
local result = lookup(ucode, options) or {}
local convert_unit = convert_lookup(ucode, value, scaled_top, want_link, nil, options)
return { text = convert_unit.text, sortkey = convert_unit.sortspan, scaled_top = convert_unit.scaled_value }
end
local function _main(values, unit_spec, options)
local number = values.number or {}
local unit_table = (unit_spec.u or unit_spec.per) and get_unit(unit_spec.u or unit_spec.per, number.value or 1, nil, options) or { text = '' }
return (number.clean or '') .. unit_table.text
end
local function main(frame)
local args = require('Module:Arguments').getArgs(frame)
local numbers = {}
local msg = get_args(numbers, args)
if msg then return valerror(msg) end
local unit_spec = { u = args.u or args.ul }
local values = { number = numbers[1] }
return _main(values, unit_spec, { want_link = args.ul ~= nil })
end
return { main = main, _main = _main }