La documentazione per questo modulo può essere creata in Modulo:GetNumber/man
--[=[ GetNumber 2023-12-31 * local nilIf (nil handling function for internal use) * local coalesce (nil handling function for internal use) * local _round (rounding function for internal use) * * local getNumbersAsTable (internal use) * * getNumbersWithUnit * getNumbersWithDate ]=] local GetNumber = {} -- it: format 1234.56 this way: 1 234,56 (as per international syntax) -- de: format 1234.56 this way: 1.234,56 (as per Italian & German syntax) local lang = mw.language.new( 'de' ) -- units and conversion -- getting conversion data from wikidata is not implemented yet local units = require ( 'Module:GetNumber/Units' ) -- returns nil, if both values are equal, otherwise the value -- similar to the SQL function nullif() local function nilIf ( value, equalValue ) if ( value == nil ) then return nil elseif ( tostring ( value ) == tostring ( equalValue ) ) then return nil else return value end end -- returns the first value that is not nil -- similar to the SQL function coalesce() local function coalesce ( value1, value2, value3 ) return value1 or value2 or value3 end -- round function, which is not available in Lua local _round = function ( value, precision ) local rescale = math.pow(10, precision or 0); return math.floor(value * rescale + 0.5) / rescale; end -- getNumbersAsTable() -> just for internal use. -- gets the amount of a property including its unit and date of validity -- id: Wikidata-ID (own, if not provided) -- property: requested property -- unit: wanted unit (standard unit, if not provided) -- if the wanted unit is not provided, a conversion will be tried based on the given conversion numbers -- values: -- - single (standard): Only one (first) entry is shown -- - all: All entries are fetched -- the functions returns a table with the folowing columns: -- amount -- unit -- unitOriginal (differs to unit, if the requested unit is converted) -- year (set to 0, if not provided) local getNumbersAsTable = function ( id, property, unit, values ) -- local variables -- ID of the item -- Determined, if not provided local localID = id or mw.wikibase.getEntityIdForCurrentPage() or '' -- compatibility to existing modules and templates: -- some use the keyword "self" for using the own entity-ID if coalesce ( nilIf ( localID, 'self' ), '' ) == '' then localID = mw.wikibase.getEntityIdForCurrentPage() or '' end -- no Wikidata object if localID == '' then return {}, '', '' end -- property local requestedProperty = property or 'none'; if string.sub(requestedProperty,1,1) ~= 'P' then requestedProperty = 'none' end -- no property given: exit if requestedProperty == 'none' then return {}, localID end -- property unknown in table "units": exit if units[requestedProperty] == nil then return {}, localID end -- unit local requestedUnit = 'none' if coalesce ( unit, '' ) == '' then if units[requestedProperty] ~= nil then requestedUnit = units[requestedProperty].standard end else requestedUnit = unit if units[requestedUnit] == nil then end end -- values local requestedValues = values or 'single' -- control variable -- is set to true, when requested unit is got on the first run local hasRequested = false -- getting the values local wdStatements = mw.wikibase.getBestStatements( localID, requestedProperty ) -- running through the array and store it in a simple table local wdValues = {} local referenceValues = {} local entryValue for i, entry in ipairs ( wdStatements ) do -- check for value if entry.mainsnak.snaktype == 'value' then -- check for number if entry.mainsnak.datatype == 'quantity' then -- new data set entryValue = {} -- getting the amount, converted into a number entryValue.amount = tonumber ( entry.mainsnak.datavalue.value.amount ) -- getting the unit entryValue.unit = entry.mainsnak.datavalue.value.unit:gsub( 'https?://www.wikidata.org/entity/', '' ) or '' -- save a copy of the original unit -- in case somebody wants to know, whether a value is converted entryValue.unitOriginal = entryValue.unit -- check, whether its the requested unit if entryValue.unit == requestedUnit then hasRequested = true end -- initialising qualifiers entryValue.year = 0 -- read qualifiers if entry.qualifiers ~= nil then -- read P585-Qualifiers (date/time of validity) if entry.qualifiers.P585 ~= nil then if entry.qualifiers.P585[1].datavalue.value.precision == 9 then entryValue.year = tonumber ( entry.qualifiers.P585[1].datavalue.value.time:sub( 2, 5 ) ) entryValue.time = entry.qualifiers.P585[1].datavalue.value.time end if entry.qualifiers.P585[1].datavalue.value.precision == 10 then entryValue.year = tonumber ( entry.qualifiers.P585[1].datavalue.value.time:sub( 2, 5 ) ) entryValue.time = entry.qualifiers.P585[1].datavalue.value.time end if entry.qualifiers.P585[1].datavalue.value.precision == 11 then entryValue.year = tonumber ( entry.qualifiers.P585[1].datavalue.value.time:sub( 2, 5 ) ) entryValue.time = entry.qualifiers.P585[1].datavalue.value.time end end -- read P2144-Qualifier (frequency) if entry.qualifiers.P2144 ~= nil then if entry.qualifiers.P2144[1].datavalue ~= nil then entryValue.P2144 = tonumber ( entry.qualifiers.P2144[1].datavalue.value.amount ) end end end referenceValues = {} -- read references if entry.references ~= nil then for j, referenceEntry in ipairs ( entry.references ) do if referenceEntry.snaks ~= nil then if referenceEntry.snaks.P854 ~= nil then if referenceEntry.snaks.P854[1].snaktype == 'value' then table.insert( referenceValues, referenceEntry.snaks.P854[1].datavalue.value ) end end end end -- for j, referenceEntry in ipairs ( entry.references ) end -- if entry.references ~= nil entryValue.references = referenceValues -- adding to the list table.insert( wdValues, entryValue ) end -- if entry.mainsnak.datatype == 'quantity' end -- if entry.mainsnak.snaktype == 'value' end -- for i, entry in ipairs ( wdStatements ) -- nothing found then exit if wdValues == {} then return {}, localID end -- generating the returning values local returnValues = {} -- controll tag, for getting all or just one value local noFetch = false -- iterating variable local i = 1 -- requested unit found? if hasRequested then -- getting the values, no conversion needed repeat -- getting a row entryValue = wdValues[i] -- put the entry to the list, if its the requested unit if entryValue.unit == requestedUnit then -- adding the row to the final result table table.insert( returnValues, entryValue ) -- stopping, if only one value is requested if requestedValues == 'single' then noFetch = true end end -- counting up i = i + 1 until noFetch or i > #wdValues -- requested unit not found -- trying conversion else -- tagging, if its succeeded at least once local conversionSuccess = true -- check, whether there is at least on data set if wdValues[i] ~= nil then -- initialize with false conversionSuccess = false -- getting the values and trying conversion repeat -- getting a row entryValue = wdValues[i] -- put the entry to the list, if the unit and conversion are available if units[entryValue.unit] ~= nil then if units[entryValue.unit].conversion[requestedUnit] ~= nil then -- adding the row to the final result table table.insert( returnValues, { amount = entryValue.amount * units[entryValue.unit].conversion[requestedUnit], unit = requestedUnit, unitOriginal = entryValue.unit, year = entryValue.year } ) -- stopping, if only one value is requested if requestedValues == 'single' then noFetch = true end -- tagging as success conversionSuccess = true end end -- counting up i = i + 1 until noFetch or i > #wdValues end end -- if hasRequested then return returnValues, localID end -- getNumbersWithUnit() -- gets the amount of a property including its unit -- first parameters: see internal function -- values: -- - single (standard): Only one (first) entry is shown -- - all: All entries are fetched -- precision: precision of the number (Standard: 0) -- show: -- - number: formatted amount without unit -- - plain: not formatted amount without unit -- - short (standard): amount with short unit -- - long: amount with long unit -- - short-date: short with date -- - short-date-ref: short with date and reference(s) -- delimiter: delimiter between the numbers; standard is comma and breakable space GetNumber.getNumbersWithUnit = function ( id, property, unit, values, precision, show, delimiter, frame ) -- returning String local numberString = '' -- making empty parameters to nil if unit == '' then unit = nil end if values == '' then values = nil end -- WD-Values local numberList local wikidataID numberList, wikidataID = getNumbersAsTable ( id, property, unit, values ) -- precision local numberPrecision = tonumber ( precision ) or 0 -- show options local numberShow = show or 'short' -- no delimiter in front of the first entry local numberDelimiter = '' if numberList[1] == nil then return nil end -- displaying the values for i, entry in ipairs( numberList ) do -- no unit given or wanted if numberShow == 'number' then numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) elseif numberShow == 'plain' then numberString = numberString .. numberDelimiter .. tostring ( entry.amount, precision ) -- displaying with unit using its long name elseif numberShow == 'long' then if units[entry.unit] ~= nil then if _round ( entry.amount, precision ) == 1 then numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].longSingle else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].long end else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) end -- displaying with unit using its abbreviation elseif numberShow == 'short-date' then if units[entry.unit] ~= nil then if entry.time ~= nil then numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].short .. ' <small>(' .. lang:formatDate( 'd.m.Y', entry.time ) .. ')</small>' else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].short end else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) end -- displaying with unit using its abbreviation elseif numberShow == 'short-date-ref' then if units[entry.unit] ~= nil then if entry.time ~= nil then numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].short .. ' <small>(' .. lang:formatDate( 'd.m.Y', entry.time ) .. ')</small>' else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].short end else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) end if #entry.references > 0 then for j, refEntry in ipairs ( entry.references ) do numberString = numberString .. frame:extensionTag{ name = 'ref', content = '[' .. refEntry .. ' ' .. refEntry .. ']' } end end -- displaying with unit using its abbreviation else if units[entry.unit] ~=nil then numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) .. ' ' .. units[entry.unit].short else numberString = numberString .. numberDelimiter .. lang:formatNum ( _round ( entry.amount, precision ) ) end end -- adding the frequency qualifikator, in case of mains voltage is requested if property == 'P2884' and entry.P2144 ~= nil then numberString = numberString .. ', ' .. entry.P2144 .. ' Hz' end -- setting the delimiter after the first entry numberDelimiter = delimiter or ', ' end -- providing the list of numbers return numberString end -- getNumbersWithDate() -- gets the amount of a property including "valid at" date -- first parameters: see internal function -- values: -- - single (standard): Only one (first) entry is shown -- - all: All entries are fetched -- show: -- - number: Only the formatted number is shown (Standard) -- - plain: Only the Not formatted number is shown -- - year: the year of validity is shown -- delimiter: delimiter between the numbers; standard is comma and breakable space GetNumber.getNumbersWithDate = function ( id, property, values, show, delimiter ) -- returning String local numberString = '' -- making empty parameters to nil if values == '' then values = nil end if show == '' then show = nil end -- setting to defaul, if necessary values = values or 'single' show = show or 'number' -- WD-Values local numberList local wikidataID -- always fetching all to be sorted later, because "singles" normally means the "most recent" numberList, wikidataID = getNumbersAsTable ( id, property, nil, 'all' ) if numberList[1] == nil then return nil end --- Sorting the table by year table.sort(numberList, function(a,b) return a.year < b.year end) -- no delimiter in front of the first entry local numberDelimiter = '' -- displaying the values if values == 'single' then -- using the first table row if show == 'year' then numberString = lang:formatNum ( numberList[1].amount ) .. ' (' .. numberList[1].year .. ')' elseif show == 'plain' then numberString = numberList[1].amount else numberString = lang:formatNum ( numberList[1].amount ) end else -- running through the table for i, entry in ipairs( numberList ) do -- adding an entry if show == 'year' then numberString = numberString .. numberDelimiter .. lang:formatNum ( entry.amount ) .. ' <span class="voy-small">(' .. entry.year .. ')</span>' elseif show == 'plain' then numberString = numberString .. numberDelimiter .. tostring ( entry.amount ) else numberString = numberString .. numberDelimiter .. lang:formatNum ( entry.amount ) end -- setting the delimiter after the first entry numberDelimiter = delimiter or ', ' end end -- providing the list of numbers return numberString end -- Providing template access local p = {} function p.getNumbersWithUnit( frame ) return GetNumber.getNumbersWithUnit( frame.args[ 1 ], frame.args[ 2 ], frame.args[ 3 ], frame.args[ 4 ], frame.args[ 5 ], frame.args.show or frame.args[ 6 ], frame.args.delimiter or frame.args[ 7 ], frame ) or "" end function p.getNumbersWithDate( frame ) return GetNumber.getNumbersWithDate( frame.args[ 1 ], frame.args[ 2 ], frame.args[ 3 ], frame.args.show or frame.args[ 4 ], frame.args.delimiter or frame.args[ 5 ] ) or "" end -- for usage in other modules -- using it the following way: -- -- local getNumber = require( 'Module:GetNumber' ) -- foo = getNumber.GetNumber().xxx( id, lang ) function p.GetNumber() return GetNumber end return p