# Module:Number table sorting

local lang = mw.language.getContentLanguage
local Math = require('Module:Math')
local SortKey = require('Module:Sortkey')
-- constants
local INF = math.huge
local NEGINF = -math.huge
local MINUS = '−' -- Unicode U+2212 MINUS SIGN (UTF-8: e2 88 92)  
---
-- Nts class
---  
local Nts = {}
Nts.__index = Nts  
Nts.formats = {
no = true,
yes = true,
}  
function Nts.new(args)
local self = setmetatable({}, Nts)  
self:parseNumber(args[1])  
-- Set the format string
self.format = args.format or 'yes'
if not Nts.formats[self.format] then
error(string.format(
"'%s' is not a valid format",
tostring(self.format)
), 0)
end  
-- To display some text before the display version of the number
-- → approx. 123,456,789.00123
self.prefix = args.prefix or ''  
-- debug info
self.debug = args.debug or 'no'
self.quiet = args.quiet or 'no'  
return self
end  
-- Parse the entered number
function Nts:parseNumber(s)
-- sanitize
s = s or '';
s = string.gsub(s,'&minus;','-')
s = string.gsub(s, MINUS, '-')
self.rawNumberString = s  
-- fractions. was somewhat but completely broken at some point
self.isFraction = (string.find(s, '/') ~= nil)
if self.isFraction then
error(string.format(
"Fractions are not supported",
tostring(s)
), 0)
end  
-- format detection
self.isScientificNotation = (string.find(s, 'e') ~= nil)  
-- parse with language options
self.number = lang:parseFormattedNumber(s)  
-- parse with fallback
if not self.number then
self.number = tonumber(s)
end  
-- allow for empty string as a value
if not self.number then
-- error(string.format(
-- "'%s' is not a valid number",
-- tostring(s)
-- ), 0)
self.number = NEGINF
end  
if self.number < 0 then
self.sign = MINUS
else
self.sign = ''
end  
self.absNumber = math.abs(self.number)
if self.absNumber ~= INF then
self.magnitude = math.floor(math.log10(self.absNumber))
self.significand = self.number / 10^self.magnitude
self.precision = Math._precision(self.rawNumberString)
self.integer = math.floor(self.absNumber)
self.fractional = math.abs(self.number - self.integer)
end
end  
function Nts:makeDisplay
local ret ={}  
if self.quiet == 'yes' then
return ''
end  
ret[#ret + 1] = self.prefix
local sciNotation = string.find(tostring(self.number),'e')
if self.absNnumber == INF or isNaN(self.number) or self.magnitude ==nil or math.abs(self.magnitude) == INF then
ret[#ret + 1] = string.gsub(self.rawNumberString, '-', MINUS)
elseif sciNotation ~= nil or math.abs(self.magnitude) >= 9 then
ret[#ret + 1] = self.sign
if self.format == 'yes' then
ret[#ret + 1] = lang:formatNum(math.abs(self.number * 10^-self.magnitude))
else
ret[#ret + 1] = math.abs(self.number * 10^-self.magnitude)
end
ret[#ret + 1] = '<span>×<span>10</span></span>
^
<sup>'
if self.magnitude<0 then
ret[#ret + 1] = MINUS .. (-self.magnitude)
else
ret[#ret + 1] = self.magnitude
end
ret[#ret + 1] = '</sup>'
else
ret[#ret + 1] = self.sign
if self.format == 'yes' then
ret[#ret + 1] = Math._precision_format(self.absNumber, self.precision)
else
local newPrecision = Math._precision(self.absNumber)
ret[#ret + 1] = tostring(self.absNumber)
if newPrecision < self.precision then
if self.integer == self.absNumber then
ret[#ret + 1] = '.'
end
ret[#ret + 1] = string.rep('0', math.min(12, self.precision - newPrecision) )
end
end
end
return table.concat(ret)
end  
function Nts:makeSortKey
return SortKey._sortKeyForNumber(self.number) .. '♠'
end  
function ifNaNThen(n,p)
if isNaN(n) then
return p
end
return n
end  
function isNaN(n)
return n ~= n
end  
function Nts:renderTrackingCategories
if self.hasDeprecatedParameters then
return ''
else
return ''
end
end  
function Nts:__tostring
local root = mw.html.create
local span = root:tag('span')
:attr('data-sort-value', self:makeSortKey)  
if self.debug == 'yes' then
span:tag('span')
:css('', ' solid')
:wikitext(self:makeSortKey)
elseif self.quiet ~= 'no' then
span:css('display', '')
end  
-- Display
if self.quiet == 'no' then
span:wikitext(self:makeDisplay)
end  
-- Tracking categories
root:wikitext(self:renderTrackingCategories)  
return tostring(root)
end  
---
-- Exports
---  
local p = {}  
function p._exportClasses
return {
Nts = Nts
}
end  
function p._main(args)
local success, ret = pcall(function
local nts = Nts.new(args)
return tostring(nts)
end)
if success then
return ret
else
ret = string.format(
'<strong>Error in Template:Nts: %s</strong>',
ret
if mw.title.getCurrentTitle.namespace == 0 then
-- Only categorise in the main namespace
ret = ret .. ''
end
return ret
end
end  
function p.main
local args = require('Module:Arguments').getArgs(, {
wrappers = { 'Template:Number table sorting' },
})
return p._main(args)
end  
return p