Module:ConvertIB explained

require('strict')local p = local getArgs = require('Module:Arguments').getArgs

-- Units accepted by that come in groups (e.g., "5 ft 6 in")local multiple =

-- Convert unit list to hashlocal mult_table = for _, v in ipairs(multiple) do mult_table[v] = trueend

-- Function to pull out values and units from numeric args-- Returns:-- values: list of numeric values, or "false" if no numeric argument is given-- units: list of units (str)-- value: if there is a last numeric value unpaired with a unit, it becomes the precision-- anyValue: whether there is a non-false value in the values listlocal function parseValuesUnits(args) local values = local units = local indx = 1 local value = nil local anyValue = false -- loop through numeric arguments in pairs while args[indx] or args[indx+1] do value = args[indx] anyValue = anyValue or value -- if there is a unit, save in output lists if args[indx+1] then table.insert(values, value or false) table.insert(units, args[indx+1]) value = nil end indx = indx+2 end return values, units, value, anyValueend

-- Function to identify multiple units and rewrite them as new input or output groups-- Args:-- values, units: numeric values and units, as lists with same length-- Returns:-- newValues, newUnits: same lists rewrittenlocal function parseMultiples(values, units) local newValues = local newUnits = local i = 1 -- we will search for multiples with up to 4 entries (depending on length) local maxMultiple = math.min(4,#units-1) local valueFound = false -- flag to suppress second (and later) input values --- Hack for handling "stone": check if only value supplied is "lb" local onlyPounds = true for i = 1, #units do if values[i] and units[i] ~= 'lb' then onlyPounds = false break end end -- sweep through units while i <= #units do -- determine index of last possible unit that could contain a multiple local last_unit = math.min(i+maxMultiple-1,#units) local multipleFound = false -- try from longest multiple down to double multiple (prefer longest ones) for j = last_unit, i+1, -1 do local key = table.concat() if mult_table[key] then -- we found a multiple unit multipleFound = true -- Hack for "stone": add either 'lb' or multiple unit string to output units -- depending on whether 'lb' was the only unit string with a value if mw.ustring.sub(key,1,2)

'st' then table.insert(newValues, false) table.insert(newUnits, onlyPounds and key or 'lb') end -- if there are any value in the span of the multiple, -- then the multiple is an input -- assume all missing values after the first are zero local firstValueFound = false for k = i, j do firstValueFound = not valueFound and (firstValueFound or values[k]) if firstValueFound then table.insert(newValues, values[k] or 0) table.insert(newUnits, units[k]) end end valueFound = valueFound or firstValueFound -- if no values in the span of the multiple, -- then the multiple is an output. Insert combined string as output unit if not firstValueFound then table.insert(newValues, false) table.insert(newUnits, key) end i = j+1 break end end --- If no multiple unit was found, insert value[i] and unit[i] into rewritten lists if not multipleFound then if valueFound then table.insert(newValues, false) -- skip writing value if it is a duplicate else table.insert(newValues,values[i]) valueFound = values[i] end table.insert(newUnits, units[i]) i = i+1 end end return newValues, newUnits end

-- Implement function p._convert(args) -- find all values and units in numeric args (and the precision, if it exists) local values, units, precision, anyValue = parseValuesUnits(args) -- bail if no values at all if not anyValue then return nil end -- rewrite values and units if multiple units are found values, units = parseMultiples(values, units) -- sort input and outputs into different buckets local input_values = local input_units = local output_units = for i = 1, #units do if values[i] then table.insert(input_values, values[i]) table.insert(input_units, units[i]) else table.insert(output_units, units[i]) end end -- bail if nothing to convert if #input_values

0 or #output_units

0 then return nil end -- assemble argument list to local innerArgs = -- First, pass all input unit(s) for i, v in ipairs(input_values) do table.insert(innerArgs,v) table.insert(innerArgs,input_units[i]) end -- Then the output unit(s) [concatenated as single argument] table.insert(innerArgs,table.concat(output_units,"+")) if precision then table.insert(innerArgs,precision) -- last non-nil value contains precision end -- now handle all non-numeric arguments, passing to innerArgs.abbr = 'on' -- abbr=on by default for k, v in pairs(args) do if not tonumber(k) then innerArgs[k] = v end end -- Call with innerArgs local frame = mw.getCurrentFrame return frame:expandTemplateend

function p.convert(frame) local args = getArgs(frame) return p._convert(args) or ""end

return p