Jump to content
Wikipedia The Free Encyclopedia

Module:ConvertIB

From Wikipedia, the free encyclopedia
Module documentation[view] [edit] [history] [purge]
Warning This Lua module is used on approximately 761,000 pages, or roughly 1% of all pages .
To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them.

A Lua module that wraps {{convert }}, designed for infoboxes. It implements:

Usage

{{#invoke:ConvertIB|convert}}

Like {{convinfobox }}, accepts alternating series of pairs of [blank|value], unit . When a unit has a non-blank value, it will get converted to all other units that do have blank values
Accepts all named parameters that {{convert }} does
Accepts groups of multiple units (e.g., "5 ft 6 in") that {{convert }} does

{{#invoke:ConvertIB|area}}

Implements {{Infobox settlement/areadisp }}, automatically converting area units, using the output order specified by MOS:UNIT

{{#invoke:ConvertIB|length}}

Implements {{Infobox settlement/lengthdisp }}, automatically converting length units, using the output order specified by MOS:UNIT

{{#invoke:ConvertIB|density}}

Implements {{Infobox settlement/densdisp }}, parsing population and area, producting density in inhabitants per square km and square mile.
The above documentation is transcluded from Module:ConvertIB/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Subpages of this module.

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

 -- 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
 localmultiple=mw.loadData('Module:ConvertIB/data').multiple
 -- 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)},'')
 ifmultiple[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

 -- Call {{convert}} with args
 localfunctioncallConvert(args)
 localframe=mw.getCurrentFrame()
 returnframe:expandTemplate{title='Convert',args=args}
 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
 returncallConvert(innerArgs)
 end

 localfunctionimpUnitPref(pref,country)
 --- lower case all arguments
 pref=prefandmw.ustring.lower(pref)
 country=countryandmw.ustring.lower(country)
 --- determine imperial unit by going thru arguments in priority order
 ifprefandpref~='dunam'then
 localimpPref=mw.loadData('Module:ConvertIB/data').impPref
 returnimpPref[pref]
 elseifcountrythen
 returnmw.ustring.find(country,"united states",1,true)
 ormw.ustring.find(country,"united kingdom",1,true)
 end
 returnfalse
 end

 locallargeUnits={km2=true,mi2=true,sqmi=true,km=true,mi=true}

 -- Implement {{Infobox settlement/areadisp}}
 functionp._area(args)
 localpref=args['pref']
 localcountry=args['name']
 localimpus=impUnitPref(pref,country)
 localdunam=args['dunam']orargs['dunum']
 locallink=args['link']
 localinnerArgs={}
 innerArgs.abbr='on'
 innerArgs.order='out'
 for_,unitinipairs({'km2','mi2','sqmi','ha','acre'})do
 ifargs[unit]then
 table.insert(innerArgs,args[unit])
 table.insert(innerArgs,unit)
 iflargeUnits[unit]then
 table.insert(innerArgs,impusand'sqmi km2'or'km2 sqmi')
 else
 table.insert(innerArgs,impusand'acre ha'or'ha acre')
 end
 returncallConvert(innerArgs)
 end
 end
 ifdunamthen
 table.insert(innerArgs,dunam)
 table.insert(innerArgs,'dunam')
 pref=prefandmw.ustring.lower(pref)
 localorder=pref=='dunam'and'dunam 'or''
 dunam=mw.getContentLanguage():parseFormattedNumber(dunam)
 ifimpusthen
 order=order..(dunamanddunam<2589and'acre ha'or'sqmi km2')
 else
 order=order..(dunamanddunam<1000and'ha acre'or'km2 sqmi')
 end
 table.insert(innerArgs,order)
 localyesNo=require('Module:Yesno')
 ifyesNo(link,true)andlink~='none'then
 innerArgs.lk='in'
 end
 returncallConvert(innerArgs)
 end
 returnnil
 end

 -- Implement {{Infobox settlement/lengthdisp}}
 functionp._length(args)
 localpref=args['pref']
 ifpref=='dunam'then-- ignore dunam pref for this function
 pref=nil
 end
 localcountry=args['name']
 localimpus=impUnitPref(pref,country)
 localinnerArgs={}
 innerArgs.abbr='on'
 innerArgs.order='out'
 for_,unitinipairs({'km','mi','m','ft'})do
 ifargs[unit]then
 table.insert(innerArgs,args[unit])
 table.insert(innerArgs,unit)
 iflargeUnits[unit]then
 table.insert(innerArgs,impusand'mi km'or'km mi')
 else
 table.insert(innerArgs,impusand'ft m'or'm ft')
 end
 returncallConvert(innerArgs)
 end
 end
 returnnil
 end

 locallang

 localfunctionparseNumeric(s)
 localnum_str=string.match(tostring(s),'^[+-]?%d[%d,]*%.?%d*e?[+-]?%d*')
 ifnotnum_strthen
 returnnil
 end
 lang=langormw.getContentLanguage()
 returnlang:parseFormattedNumber(num_str)
 end

 --Compute number of significant digits in a numeric string
 localfunctioncomputeSigFig(s)
 localnum_str=string.match(tostring(s),'^[+-]?%d[%d,]*%.?%d*')
 ifnotnum_strthen
 return0
 end

 -- Strip leading signs
 num_str=string.gsub(num_str,'^[+-]','')
 -- Strip commas
 num_str=string.gsub(num_str,',','')
 -- Strip leading zeros
 num_str=string.gsub(num_str,'^0*','')

 ifnum_str==''then
 return0
 end

 -- If there's a decimal point, all trailing zeros are significant.
 ifstring.find(num_str,'%.')then
 return#string.gsub(num_str,'%.','')-- Count all digits after removing decimal
 end

 -- If no decimal point, trailing zeros are not significant.
 -- Count all digits up to the last non-zero one.
 num_str=string.gsub(num_str,'0+$','')

 return#num_str
 end

 -- Implement {{Infobox settlement/densdisp}}
 -- Returns table:
 -- density = computed value if no error
 -- error = error string if error. 
 -- These are only errors detected in this code, {{convert}} does its own error handling
 functionp._density(args)
 localresult={}
 localpref=args['pref']
 ifpref=='dunam'then-- ignore dunam pref for this function
 pref=nil
 end
 localcountry=args['name']
 localper_km2=args['/km2']
 localper_mi2=args['/mi2']orargs['/sqmi']
 localimpus=impUnitPref(pref,country,per_km2,per_mi2)
 localper_km2_value=parseNumeric(per_km2)
 localper_mi2_value=parseNumeric(per_mi2)
 localinnerArgs={}
 innerArgs.abbr='on'
 ifper_km2_valueorper_mi2_valuethen
 innerArgs.order='out'
 ifper_km2_valuethen
 table.insert(innerArgs,per_km2_value)
 table.insert(innerArgs,'/km2')
 else
 table.insert(innerArgs,per_mi2_value)
 table.insert(innerArgs,'/sqmi')
 end
 table.insert(innerArgs,impusand'/sqmi /km2'or'/km2 /sqmi')
 result.density=callConvert(innerArgs)
 returnresult
 end
 ifper_km2~='auto'andper_mi2~='auto'then
 -- automatic computation not requested, fail silently
 returnresult
 end
 ifnotargs['pop']then
 -- fail silently if no population given
 returnresult
 end
 localareaSigFig
 localareaValue
 localareaUnit
 for_,unitinipairs({'km2','mi2','sqmi','ha','acre','dunam','dunum'})do
 localvalue=parseNumeric(args[unit])
 ifvaluethen
 ifvalue<=0then
 result.error=unit.." value not positive"
 returnresult
 end
 areaValue=value
 areaUnit=unit
 areaSigFig=computeSigFig(args[unit])
 break
 elseifargs[unit]then
 result.error="Malformed "..unit.." value"
 returnresult
 end
 end
 ifnotareaSigFigthen
 -- fail silently if no area given
 returnresult
 end
 ifareaSigFig==0then
 result.error="Malformed area string"
 returnresult
 end
 localpopValue=parseNumeric(args['pop'])
 ifnotpopValuethen
 result.error="Malformed population value"
 returnresult
 end
 ifpopValue<0then
 result.error="Negative population value"
 returnresult
 end
 table.insert(innerArgs,popValue/areaValue)
 table.insert(innerArgs,'/'..areaUnit)
 localpopSigFig=computeSigFig(args['pop'])
 localsigFig=popSigFig<areaSigFigandpopSigFigorareaSigFig
 ifsigFig<2then
 sigFig=2
 end
 innerArgs.sigfig=sigFig
 innerArgs.disp='out'
 table.insert(innerArgs,'/km2')
 localmetric=callConvert(innerArgs)
 innerArgs[3]='/sqmi'
 localimperial=callConvert(innerArgs)
 ifimpusthen
 result.density=string.format("%s (%s)",imperial,metric)
 else
 result.density=string.format("%s (%s)",metric,imperial)
 end
 returnresult
 end

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

 functionp.area(frame)
 localargs=getArgs(frame)
 returnp._area(args)or""
 end

 functionp.length(frame)
 localargs=getArgs(frame)
 returnp._length(args)or""
 end

 functionp.density(frame)
 localargs=getArgs(frame)
 localresult=p._density(args)
 ifresult.densitythen
 returnresult.density
 end
 ifresult.errorthen
 localwarning=require('Module:If_preview')._warning
 localresult=warning({result.error})
 ifmw.title.getCurrentTitle().namespace==0then
 result=result..'[[Category:Pages using infobox settlement with bad density arguments]]'
 end
 returnresult
 end
 return''
 end

 returnp

AltStyle によって変換されたページ (->オリジナル) /