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 .. ',&nbsp;' .. entry.P2144 .. '&#x202F;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 ) .. '&#x202F;<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