Jump to content

Module:ConvertIB

Permanently protected module
From Wikipedia, the free encyclopedia

require('strict')
localp={}
localgetArgs=require('Module:Arguments').getArgs

-- Units accepted by {{convert}} that come in groups (e.g., "5 ft 6 in" )
localmultiple=
{'mich','michlk','michainlk','miyd','miydftin','mift','ydftin','ydft',
'ftin','footin','handin','lboz','stlb','stlboz','stlb'}

-- Convert unit list to hash
localmult_table={}
for_,vinipairs(multiple)do
mult_table[v]=true
end

-- 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 list
localfunctionparseValuesUnits(args)
localvalues={}
localunits={}
localindx=1
localvalue=nil
localanyValue=false
-- loop through numeric arguments in pairs
whileargs[indx]orargs[indx+1]do
value=args[indx]
anyValue=anyValueorvalue
-- if there is a unit, save in output lists
ifargs[indx+1]then
table.insert(values,valueorfalse)
table.insert(units,args[indx+1])
value=nil
end
indx=indx+2
end
returnvalues,units,value,anyValue
end

-- 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 rewritten
localfunctionparseMultiples(values,units)
localnewValues={}
localnewUnits={}
locali=1
-- we will search for multiples with up to 4 entries (depending on length)
localmaxMultiple=math.min(4,#units-1)
localvalueFound=false-- flag to suppress second (and later) input values
--- Hack for handling "stone": check if only value supplied is "lb"
localonlyPounds=true
fori=1,#unitsdo
ifvalues[i]andunits[i]~='lb'then
onlyPounds=false
break
end
end
-- sweep through units
whilei<=#unitsdo
-- determine index of last possible unit that could contain a multiple
locallast_unit=math.min(i+maxMultiple-1,#units)
localmultipleFound=false
-- try from longest multiple down to double multiple (prefer longest ones)
forj=last_unit,i+1,-1do
localkey=table.concat({unpack(units,i,j)},'')
ifmult_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
ifmw.ustring.sub(key,1,2)=='st'then
table.insert(newValues,false)
table.insert(newUnits,onlyPoundsandkeyor'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
localfirstValueFound=false
fork=i,jdo
firstValueFound=notvalueFoundand(firstValueFoundorvalues[k])
iffirstValueFoundthen
table.insert(newValues,values[k]or0)
table.insert(newUnits,units[k])
end
end
valueFound=valueFoundorfirstValueFound
-- if no values in the span of the multiple,
-- then the multiple is an output. Insert combined string as output unit
ifnotfirstValueFoundthen
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
ifnotmultipleFoundthen
ifvalueFoundthen
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
returnnewValues,newUnits
end

-- Implement {{convinfobox}}
functionp._convert(args)
-- find all values and units in numeric args (and the precision, if it exists)
localvalues,units,precision,anyValue=parseValuesUnits(args)
-- bail if no values at all
ifnotanyValuethen
returnnil
end
-- rewrite values and units if multiple units are found
values,units=parseMultiples(values,units)
-- sort input and outputs into different buckets
localinput_values={}
localinput_units={}
localoutput_units={}
fori=1,#unitsdo
ifvalues[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==0or#output_units==0then
returnnil
end
-- assemble argument list to {{convert}}
localinnerArgs={}
-- First, pass all input unit(s)
fori,vinipairs(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,"+"))
ifprecisionthen
table.insert(innerArgs,precision)-- last non-nil value contains precision
end
-- now handle all non-numeric arguments, passing to {{convert}}
innerArgs.abbr='on'-- abbr=on by default
fork,vinpairs(args)do
ifnottonumber(k)then
innerArgs[k]=v
end
end
-- Call {{convert}} with innerArgs
localframe=mw.getCurrentFrame()
returnframe:expandTemplate{title='Convert',args=innerArgs}
end

functionp.convert(frame)
localargs=getArgs(frame)
returnp._convert(args)or""
end

returnp