Module:Convert: Difference between revisions

Content deleted Content added
handle outputs with multiple units like 'ftin' (and 'miydftin'); more refactoring
move code from Module:Convertdata to here; improve lookup() to handle a combination with a component that is a multiple
Line 6:
-- A testing program can set the global variable 'is_test_run'.
local convertdata = require(is_test_run and "convertdata" or "Module:Convertdata")
local SIprefixes = convertdata.SIprefixes
local units = convertdata.units
local default_exceptions = convertdata.default_exceptions
Line 41 ⟶ 42:
end
return cfg
end
 
local function clonetable(t)
-- Return a shallow copy of t.
local result = {}
for k, v in pairs(t) do
result[k] = v
end
return result
end
 
local function shouldbe(ucode, shouldbe)
-- Return an error message for a unit that "should be" something else.
-- Old Template:Convert outputs a much more elaborate message.
-- LATER: Decide if "shouldbe" is useful, and what to output if it is.
return 'ERROR: Use "' .. shouldbe .. '" (not "' .. ucode .. '") as the unit code.'
end
 
local usesubstitute = {
-- If unit has an SI prefix, these fields may have "%s" where prefix belongs.
'name1',
'name1_us',
'name2',
'name2_us',
}
 
local function set_prefixes(unit, prefixname)
-- Insert given prefix name into the fields which require it
-- (and which should contain '%s' to be replaced with the prefix).
-- Pity we have to do all this work when most results are not needed,
-- but it's cleaner to do it here rather than in final processing.
if unit.prefixes then
for _, name in ipairs(usesubstitute) do
local value = unit[name]
unit[name] = value:gsub('%%s', prefixname, 1)
end
end
end
 
local function lookup(unit, sp, what)
-- Return true, t where t is the unit's converter table (or false, message).
-- Parameter 'sp' is 'us' for US spelling of prefixes, or nil.
-- Parameter 'what' determines whether combination units are accepted:
-- 'no_combination' : single unit only
-- 'any_combination' : single unit or combination or multiple
-- 'only_multiple' : single unit or multiple only
-- Parameter 'unit' is a symbol (like 'g'), with an optional SI prefix (like 'kg').
-- If, for example, 'kg' is in this table, that entry is used;
-- otherwise the prefix ('k') is applied to the base unit ('g').
-- If the 'unit' is a known combination code (and if allowed by what),
-- a table of multiple unit tables is included in the result.
if unit == nil or unit == '' then
return false, 'Need name of unit'
end
local t = units[unit]
if t ~= nil then
if t.shouldbe then
return false, shouldbe(t.shouldbe, unit)
end
local combo = t.combination -- nil or a table of unitcodes
if combo then
local multiple = t.multiple
if what == 'no_combination' or (what == 'only_multiple' and multiple == nil) then
local msg = 'Unit "%s" is invalid here.[[Category:Convert unknown unit]]'
return false, msg:format(unit)
end
-- Recursively create a combination table containing the
-- converter table of each unitcode.
local success
local result = { utype = t.utype, multiple = multiple, combination = {} }
local cvt = result.combination
for i, v in ipairs(combo) do
success, cvt[i] = lookup(v, sp, multiple and 'no_combination' or 'only_multiple')
if not success then return false, cvt[i] end
end
return true, result
end
local result = clonetable(t)
set_prefixes(result, '')
result.baseunit = unit
result.prefix = ''
return true, result
end
for plen = 2, 1, -1 do
-- Check for longer prefix first ('dam' is decametre).
-- Micro (µ) is two bytes in utf-8, so is found with plen = 2.
local prefix = string.sub(unit, 1, plen)
local si = SIprefixes[prefix]
if si then
local baseunit = unit:sub(plen+1)
local t = units[baseunit]
if t and t.prefixes then
local result = clonetable(t)
local name
if sp == 'us' or t.sp_us then
name = si.name_us
else
name = si.name
end
set_prefixes(result, name)
prefix = si.prefix -- what prefix should be
result.symbol = prefix .. result.symbol
result.sym_us = prefix .. result.sym_us
result.baseunit = baseunit
result.prefix = prefix
result.scale = t.scale * 10 ^ (si.exponent * t.prefixes)
return true, result
end
end
end
local msg = 'Unit "%s" is not known.[[Category:Convert unknown unit]]'
return false, msg:format(unit)
end
 
Line 497 ⟶ 610:
i = 5
end
local success, in_unit_table = units:lookup(in_unit, args.sp, 'no_combination')
if not success then return false, in_unit_table end
in_unit_table.valinfo = { info1, info2 } -- info2 is nil if no range
Line 1,106 ⟶ 1,219:
end
local out_unit_table
local success, t = units:lookup(parms.out_unit, parms.sp, true'any_combination')
if success then out_unit_table = t else return false, t end
if in_unit_table.utype ~= out_unit_table.utype then