Module:Gapnum: Difference between revisions

From Zoophilia Wiki
Jump to navigationJump to search
meta>The Mol Man
No edit summary
meta>The Mol Man
No edit summary
Line 144: Line 144:
-- Preference for groups of 4 instead of groups of 1 at the end
-- Preference for groups of 4 instead of groups of 1 at the end
if #frac_part % 3 == 1 then
if #frac_part % 3 == 1 then
local last_g = ret_d[#ret_d]
local last_g = ret_d[#ret_d] or ''
last_g = last_g..frac_part:sub(-1)
last_g = last_g..frac_part:sub(-1)
ret_d[#ret_d] = last_g
ret_d[#ret_d] = last_g

Revision as of 02:03, 8 January 2015

Documentation for this module may be created at Module:Gapnum/doc

local p = {}

local getArgs

function p.main(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	local args = getArgs(frame, {wrappers = 'Template:Gapnum'})
	local n = args[1]

	if not n then
		error('Parameter 1 is required')
	elseif not tonumber(n) then
		error('Unable to convert "' .. args[1] .. '" to a number')
	end

	local gap = args.gap
	local precision = tonumber(args.prec)

	return p.gaps(n,{gap=gap,prec=precision})
end

-- Not named p._main so that it has a better function name when required by Module:Val
function p.gaps(n,tbl)
	local nstr = tostring(n)
	if not tbl then
		tbl = {}
	end
	local gap = tbl.gap or '.25em'
	local precision = tbl.prec or -1

	local decimalloc = nstr:find('.', 1, true)
	local int_part, frac_part
	if decimalloc == nil then
		int_part = nstr
	else
		int_part = nstr:sub(1, decimalloc-1)
		frac_part = nstr:sub(decimalloc + 1)
	end
	local ret = mw.html.create('span')
							:css('white-space','nowrap')
	local int_string = {}
	-- Loop to handle most of the groupings; from right to left, so that if a group has less than 3 members, it will be the first group
	-- ???: Would string.reverse with string.gmatch be better??
	while int_part:len() > 3 do
		-- Insert in first spot, since we're moving backwards
		table.insert(int_string,1,int_part:sub(-3))
		int_part = int_part:sub(1,-4)
	end
	-- handle any left over numbers; add directly
	ret:wikitext(int_part)
	-- Build intstring
	for _, v in ipairs(int_string) do
		ret:tag('span')
				:css('margin-left',gap)
				:wikitext(v)
			:done()
	end

	if precision ~= 0 and frac_part then
		ret:wikitext('.')
		if precision == -1 then
			precision = frac_part:len()
		end
		-- Reduce the length of the string if required precision is less than actual precision
		-- OR
		-- Increase it (by adding 0s) if the required precision is more than actual
		local offset = precision - frac_part:len()
		if offset < 0 then
			frac_part = frac_part:sub(1,precision)
		elseif offset > 0 then
			frac_part = frac_part .. string.rep('0', offset)
		end
		-- The first group after the decimal shouldn't have a gap between the decimal
		ret:wikitext(frac_part:sub(1,3))
		frac_part = frac_part:sub(4)
		local last_span
		-- Allow groups of 3 or 2 (3 first)
		for v in string.gmatch(frac_part,'%d%d%d?') do
			last_span = ret:tag('span')
					:css('margin-left',gap)
					:wikitext(v)
		end
		-- Preference for groups of 4 instead of groups of 1 at the end
		if #frac_part % 3 == 1 then
			if last_span then
				last_span:wikitext(frac_part:sub(-1))
			else
				ret:wikitext(frac_part)
			end
		end
	end

	return ret
end

-- Creates tables where each element is a different group of the number
function p.groups(num,precision)
	local nstr = tostring(num)
	if not precision then
		precision = -1
	end

	local decimalloc = nstr:find('.', 1, true)
	local int_part, frac_part
	if decimalloc == nil then
		int_part = nstr
	else
		int_part = nstr:sub(1, decimalloc-1)
		frac_part = nstr:sub(decimalloc + 1)
	end
	local ret_i,ret_d = {}
	-- Loop to handle most of the groupings; from right to left, so that if a group has less than 3 members, it will be the first group
	while int_part:len() > 3 do
		-- Insert in first spot, since we're moving backwards
		table.insert(ret_i,1,int_part:sub(-3))
		int_part = int_part:sub(1,-4)
	end
	-- handle any left over numbers
	if int_part:len() > 0 then
		table.insert(ret_i,1,int_part)
	end

	if precision ~= 0 and frac_part then
		ret_d = {}
		if precision == -1 then
			precision = frac_part:len()
		end
		-- Reduce the length of the string if required precision is less than actual precision
		-- OR
		-- Increase it (by adding 0s) if the required precision is more than actual
		local offset = precision - frac_part:len()
		if offset < 0 then
			frac_part = frac_part:sub(1,precision)
		elseif offset > 0 then
			frac_part = frac_part .. string.rep('0', offset)
		end

		-- Allow groups of 3 or 2 (3 first)
		for v in string.gmatch(frac_part,'%d%d%d?') do
			table.insert(ret_d,v)
		end
		-- Preference for groups of 4 instead of groups of 1 at the end
		if #frac_part % 3 == 1 then
			local last_g = ret_d[#ret_d] or ''
			last_g = last_g..frac_part:sub(-1)
			ret_d[#ret_d] = last_g
		end
	end
	if ret_d then
		return ret_i,ret_d
	else
		return ret_i
	end
end
return p