Module:Convert: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
(update from sandbox per Template talk:Convert#Module version 8) |
(update from sandbox per Template talk:Convert#Module version 9) |
||
Line 139: | Line 139: | ||
local speller -- function from that module to handle spelling (set if spelling is wanted) |
local speller -- function from that module to handle spelling (set if spelling is wanted) |
||
local function set_config( |
local function set_config(args) |
||
-- Set configuration options from template #invoke or defaults. |
-- Set configuration options from template #invoke or defaults. |
||
config = |
config = args |
||
maxsigfig = config.maxsigfig or 14 -- maximum number of significant figures |
maxsigfig = config.maxsigfig or 14 -- maximum number of significant figures |
||
local data_module, text_module |
local data_module, text_module |
||
Line 243: | Line 243: | ||
if type(text) == 'string' then |
if type(text) == 'string' then |
||
return text:match("^%s*(.-)%s*$") |
return text:match("^%s*(.-)%s*$") |
||
end |
|||
end |
|||
local function table_len(t) |
|||
-- Return length (<100) of a numbered table to replace #t which is |
|||
-- documented to not work if t is accessed via mw.loadData(). |
|||
for i = 1, 100 do |
|||
if t[i] == nil then |
|||
return i - 1 |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 539: | Line 549: | ||
local unit_per_mt = { |
local unit_per_mt = { |
||
-- Metatable to get values for a |
-- Metatable to get values for a per unit of form "x/y". |
||
-- This is never called to determine a unit name or link because |
-- This is never called to determine a unit name or link because per units |
||
-- are handled as a special case. |
-- are handled as a special case. |
||
-- Similarly, the default output is handled elsewhere. |
-- Similarly, the default output is handled elsewhere. |
||
Line 568: | Line 578: | ||
local function make_per(unit_table, force_sp_us, ulookup) |
local function make_per(unit_table, force_sp_us, ulookup) |
||
-- Return true, t where t is a |
-- Return true, t where t is a per unit with unit codes expanded to unit tables, |
||
-- or return false, t where t is an error message table. |
-- or return false, t where t is an error message table. |
||
local result = { utype = unit_table.utype, per = {} } |
local result = { utype = unit_table.utype, per = {} } |
||
Line 590: | Line 600: | ||
local multiplier = unit_table.multiplier |
local multiplier = unit_table.multiplier |
||
if not result.utype then |
if not result.utype then |
||
-- Creating an automatic |
-- Creating an automatic per unit. |
||
local unit1 = result.per[1] |
local unit1 = result.per[1] |
||
local utype = (unit1 and unit1.utype or prefix or '') .. '/' .. result.per[2].utype |
local utype = (unit1 and unit1.utype or prefix or '') .. '/' .. result.per[2].utype |
||
Line 789: | Line 799: | ||
local top, bottom = unitcode:match('^(.-)/([^/]+)$') |
local top, bottom = unitcode:match('^(.-)/([^/]+)$') |
||
if top and not unitcode:find('e%d') then |
if top and not unitcode:find('e%d') then |
||
-- If valid, create an automatic |
-- If valid, create an automatic per unit for an "x/y" unit code. |
||
-- The unitcode must not include extraneous spaces. |
-- The unitcode must not include extraneous spaces. |
||
-- Engineering notation (apart from at start and which has been stripped before here), |
-- Engineering notation (apart from at start and which has been stripped before here), |
||
Line 1,622: | Line 1,632: | ||
end |
end |
||
local function range_text(range, want_name, parms, before, after) |
local function range_text(range, want_name, parms, before, after, inout) |
||
-- Return before .. rtext .. after |
-- Return before .. rtext .. after |
||
-- where rtext is the text that separates two values in a range. |
-- where rtext is the text that separates two values in a range. |
||
local rtext, adj_text, exception |
local rtext, adj_text, exception |
||
if type(range) == 'table' then |
if type(range) == 'table' then |
||
-- Table must specify range text for |
-- Table must specify range text for ('off' and 'on') or ('input' and 'output'), |
||
-- and may specify range text for 'adj=on', |
-- and may specify range text for 'adj=on', |
||
-- and may specify exception = true. |
-- and may specify exception = true. |
||
rtext = range[want_name and 'off' or 'on'] |
rtext = range[want_name and 'off' or 'on'] or |
||
range[((inout == 'in') == (parms.opt_flip == true)) and 'output' or 'input'] |
|||
adj_text = range['adj'] |
adj_text = range['adj'] |
||
exception = range['exception'] |
exception = range['exception'] |
||
Line 1,901: | Line 1,912: | ||
-- used instead of "3+1/2" (and which should not be interpreted as "3 to ½"). |
-- used instead of "3+1/2" (and which should not be interpreted as "3 to ½"). |
||
-- Unpacked items are inserted into the parms table. |
-- Unpacked items are inserted into the parms table. |
||
⚫ | |||
local valstr = strip(parms[i]) -- trim so any '-' as a negative sign will be at start |
local valstr = strip(parms[i]) -- trim so any '-' as a negative sign will be at start |
||
local success, result = extract_number(parms, valstr, i > 1) |
local success, result = extract_number(parms, valstr, i > 1) |
||
if not success and valstr |
if not success and valstr and i < 20 then -- check i to limit abuse |
||
local lhs, sep, rhs = valstr:match('^(%S+)%s+(%S+)%s+(%S.*)') |
|||
⚫ | |||
if lhs and not (sep == '-' and rhs:match('/')) then |
|||
⚫ | |||
if |
if sep:find('%d') then |
||
return success, result -- to reject {{convert|1 234 567|m}} with a decent message (en only) |
|||
⚫ | |||
end |
|||
⚫ | |||
parms[i] = rhs |
|||
table.insert(parms, i, sep) |
|||
⚫ | |||
table.insert(parms, i, lhs) |
|||
return extractor(i) |
|||
end |
|||
if not valstr:match('%-.*/') then |
|||
⚫ | |||
⚫ | |||
if start then |
|||
⚫ | |||
⚫ | |||
table.insert(parms, i, valstr:sub(1, start - 1)) |
|||
return extractor(i) |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 1,977: | Line 2,001: | ||
end |
end |
||
local function get_parms( |
local function get_parms(args) |
||
-- If successful, return true, parms, unit where |
-- If successful, return true, parms, unit where |
||
-- parms is a table of all arguments passed to the template |
-- parms is a table of all arguments passed to the template |
||
Line 1,991: | Line 2,015: | ||
local parms = {} -- arguments passed to template, after translation |
local parms = {} -- arguments passed to template, after translation |
||
local kv_pairs = {} -- table of input key:value pairs where key is a name; needed because cannot iterate parms and add new fields to it |
local kv_pairs = {} -- table of input key:value pairs where key is a name; needed because cannot iterate parms and add new fields to it |
||
for k, v in pairs( |
for k, v in pairs(args) do |
||
if type(k) == 'number' or k == 'test' then -- parameter "test" is reserved for testing and is not translated |
if type(k) == 'number' or k == 'test' then -- parameter "test" is reserved for testing and is not translated |
||
parms[k] = v |
parms[k] = v |
||
Line 2,571: | Line 2,595: | ||
if combo then |
if combo then |
||
-- For a multiple like ftin, the "first" unit (ft) is last in the combination. |
-- For a multiple like ftin, the "first" unit (ft) is last in the combination. |
||
local i = t.multiple and |
local i = t.multiple and table_len(combo) or 1 |
||
ucode = combo[i] |
ucode = combo[i] |
||
end |
end |
||
Line 2,981: | Line 3,005: | ||
-- For simplicity and because more not needed, handle one range item only. |
-- For simplicity and because more not needed, handle one range item only. |
||
local prefix2 = make_id(parms, 2, first_unit) .. ' ' |
local prefix2 = make_id(parms, 2, first_unit) .. ' ' |
||
result = range_text(range[1], want_name, parms, result, prefix2 .. valinfo[2].show) |
result = range_text(range[1], want_name, parms, result, prefix2 .. valinfo[2].show, 'in') |
||
end |
end |
||
return preunit .. result |
return preunit .. result |
||
Line 3,049: | Line 3,073: | ||
result = valinfo[1].show |
result = valinfo[1].show |
||
end |
end |
||
result = range_text(range[1], want_name, parms, result, valinfo[2].show) |
result = range_text(range[1], want_name, parms, result, valinfo[2].show, 'in') |
||
else |
else |
||
-- Like {{convert|1|x|2|x|3|ft}} (two or more range items): simplify. |
-- Like {{convert|1|x|2|x|3|ft}} (two or more range items): simplify. |
||
Line 3,056: | Line 3,080: | ||
for i = 1, range.n do |
for i = 1, range.n do |
||
decorate_value(parms, in_current, i+1) |
decorate_value(parms, in_current, i+1) |
||
result = range_text(range[i], want_name, parms, result, valinfo[i+1].show) |
result = range_text(range[i], want_name, parms, result, valinfo[i+1].show, 'in') |
||
end |
end |
||
end |
end |
||
Line 3,090: | Line 3,114: | ||
if range then |
if range then |
||
-- For simplicity and because more not needed, handle one range item only. |
-- For simplicity and because more not needed, handle one range item only. |
||
result = range_text(range[1], want_name, parms, result, prefix .. valinfo[2].show) |
result = range_text(range[1], want_name, parms, result, prefix .. valinfo[2].show, 'out') |
||
end |
end |
||
return preunit .. result |
return preunit .. result |
||
Line 3,121: | Line 3,145: | ||
result = valinfo[1].show |
result = valinfo[1].show |
||
end |
end |
||
result = range_text(range[1], want_name, parms, result, valinfo[2].show) |
result = range_text(range[1], want_name, parms, result, valinfo[2].show, 'out') |
||
else |
else |
||
-- Like {{convert|1|x|2|x|3|ft}} (two or more range items): simplify. |
-- Like {{convert|1|x|2|x|3|ft}} (two or more range items): simplify. |
||
Line 3,128: | Line 3,152: | ||
for i = 1, range.n do |
for i = 1, range.n do |
||
decorate_value(parms, out_current, i+1) |
decorate_value(parms, out_current, i+1) |
||
result = range_text(range[i], want_name, parms, result, valinfo[i+1].show) |
result = range_text(range[i], want_name, parms, result, valinfo[i+1].show, 'out') |
||
end |
end |
||
end |
end |
||
Line 3,297: | Line 3,321: | ||
local success, result2 = make_result(valinfo[i+1]) |
local success, result2 = make_result(valinfo[i+1]) |
||
if not success then return false, result2 end |
if not success then return false, result2 end |
||
result = range_text(range[i], want_name, parms, result, result2) |
result = range_text(range[i], want_name, parms, result, result2, 'out') |
||
end |
end |
||
end |
end |
||
Line 3,446: | Line 3,470: | ||
local function main_convert(frame) |
local function main_convert(frame) |
||
-- Do convert, and if needed, do it again with higher default precision. |
-- Do convert, and if needed, do it again with higher default precision. |
||
set_config(frame) |
set_config(frame.args) |
||
local result, out_unit_table |
local result, out_unit_table |
||
local success, parms, in_unit_table = get_parms(frame:getParent()) |
local success, parms, in_unit_table = get_parms(frame:getParent().args) |
||
if success then |
if success then |
||
for i = 1, 2 do -- use counter so cannot get stuck repeating convert |
for i = 1, 2 do -- use counter so cannot get stuck repeating convert |