require('strict')
local fn = require('Module:Formatnum')
local mm = require('Module:Math')
local p ={}
local pargs ={}
function p.lighthouse(frame)
local page = frame.args['page']
local qid = frame.args['qid']
local property = frame.args['property']
local text = page .. ": instance of :"
--local item = mw.wikibase.getEntity('P'..prop) --('P5354')
if page then
qid = mw.wikibase.getEntityIdForTitle(page)
text = page .. ': instance of :'
elseif qid then
text = mw.wikibase.getLabel(qid) .. ' (' .. qid .. '): instance of :'
else
return "No page or qid given"
end
local statements = mw.wikibase.getBestStatements(qid, 'P31') -- get instance of
for index, statement in pairs( statements ) do
local instanceOfId
if statement and statement.mainsnak and statement.mainsnak.datavalue then
instanceOfId = statement.mainsnak.datavalue.value.id
text = text .. '\n:::' .. instanceOfId .. ' (' .. mw.wikibase.getLabel(instanceOfId) .. ') '
--local item2 = mw.wikibase.getEntity(instanceOfId) -- returns full claims table [expensive,so just use best statements]
--local statements2 = item2:getBestStatements( 'P279')
local instanceOfStatements = mw.wikibase.getBestStatements(instanceOfId, 'P279')
text = text .. '[subclass: '
for _, instanceOfStatement in pairs( instanceOfStatements ) do
if instanceOfStatement.mainsnak and instanceOfStatement.mainsnak.datavalue then
local subclassId = instanceOfStatement.mainsnak.datavalue.value.id
text = text .. '\n:::::' .. subclassId .. ' (' .. mw.wikibase.getLabel(subclassId) .. ') '
end
end
text = text .. ']; '
end
end
return text
end
function p.testExpensive(frame, page, mode)
local mode = frame.args['mode']
if not mode then mode = "makeTitle" end
local title
local page = frame.args['page']
if not page then p.errormsg("Target page not found") end -- TODO check for page existence here
if mode == "new" then
title = mw.title.new( page) -- , ns)
else
title = mw.title.makeTitle( "Template", page)
end
if not title then return p.errormsg("Title object not created") end
if not title.exists then
return "Invalid page name = " .. title.text .. " (using mw.title." .. mode .. ")"
end
return "Title = " ..title.text .. " (using mw.title." .. mode .. ")"
end
function p.getdomain(frame)
local url = frame.args[1]
local domain = string.match( url, "%/%/(.-)%/" )
local domain2 = mw.uri.new(url).host
return domain .. "|" .. domain2
end
function p.getclade(frame)
local page = frame.args['page']
if not page then p.errormsg("Target page not found") end -- TODO check for page existence here
local title = mw.title.new( page) -- , ns)
if not title then p.errormsg("Title not retrieved from page") end
local content = title:getContent()
local cladogram = p.matchClade(content)
if 1==2 then
return frame:preprocess(p.matchClade(cladogram))
else -- now do something with it
return p.parseCladogram(frame, cladogram)
end
end
function p.parseCladogram(frame, cladogram)
local pattern = '|1=(.+)[|}]'
--local value = p.matchClade(cladogram, pattern)
for match in cladogram:gmatch(pattern) do -- most inclusive
if match:find("^{{clade") then
local value = p.matchClade(match)
return p.parseCladogram(frame, value)
--return frame:preprocess(p.matchClade(match)) --found clade
else
return "no clade found" .. match
end
return "no match found in match : " ..match
end
--return frame:preprocess(value)
return "no match found in cladogram: " .. cladogram
end
function p.matchClade(content, pattern)
if not pattern then
pattern = '{{clade.-}}' -- least inclusive (until first "}}")
pattern = '{{clade.+}}' -- most inclusive (until last "}}", e.g. the taxonbar close)
end
for match in content:gmatch(pattern) do -- most inclusive
for match2 in match:gmatch('%b{}') do -- match paired brackets
return match2
end
end
end
function p.getpage(frame)
local page = frame.args['page']
local wrap = frame.args['wrap']
if not page then p.errormsg("Target page not found") end -- TODO check for page existence here
local title = mw.title.new( page) -- , ns)
if title then
local content = title:getContent()
if wrap then
content = '<' .. wrap .. '>' .. tostring(content) .. '</' .. wrap .. '>'
end
return content
end
end
p.main = function(frame) -- called from template
pargs = frame:getParent().args
local output
local page = pargs['page']
if not page then p.errormsg("Target page not found") end -- TODO check for page existence here
local section = pargs['section'] or pargs['section1'] or pargs[1]
if section then
output = p._section(frame, page, section)
end
local label = pargs['label'] or pargs['label1'] or pargs[1]
if label then
output = p._label(frame, page, label)
end
local subtree = pargs['subtree'] or pargs['subtree1'] or pargs[1]
if subtree then
output = p._label(frame, page, subtree)
end
local wrap = pargs['wrap']
if wrap and (label or subtree) then
local label1 = label or string.lower(subtree)
if wrap ~= "" then label1 = wrap end
output = "{{clade |label1=" .. p.firstToUpper(label1) .. "|1=" .. output .. "}}"
end
if output then
return frame:preprocess(output)
end
return p.errormsg("No valid option for transclusion")
end
p.test = function(frame)
--mw.title.makeTitle( namespace, title, fragment, interwiki )
--mw.title.new( text, namespace )
local page = "User:Jts1882/sandbox/test/Passeriformes" --"Atelopus andinus"
local section = "Passeriformes"
local ns = 1
if page:find("^User") then ns = 2 end
if page:find("^Template") then ns = 10 end -- TODO check number
--mw.site.namespaces.User.id -- returns 2
--TEST PAGE = User:Jts1882/sandbox
return p._section(frame,page, "Passeroidea ", "Corvida", "Tyranni")
end
p.test_working_prototype = function(frame)
--mw.title.makeTitle( namespace, title, fragment, interwiki )
--mw.title.new( text, namespace )
local page = "User:Jts1882/sandbox/test/Passeriformes" --"Atelopus andinus"
local ns = 1
if page:find("^User") then ns = 2 end
if page:find("^Template") then ns = 10 end -- TODO check number
--mw.site.namespaces.User.id -- returns 2
--TEST PAGE = User:Jts1882/sandbox
local title = mw.title.new( page) -- , ns)
if title then
local content = title:getContent()
local pattern = "<section begin=Passeriformes />(.+)<section end=Passeriformes />"
pattern = "{{#tag:section||begin=Test}}(.+){{#tag:section||end=Test}}"
local value = string.match( content , pattern )
if value then
return frame:preprocess(value)
--return value
else
return "no match found"
end
return content
end
return "Hello"
end
--================================== exclude LABEL ================================================
p.xlabel = function (frame, page, ...)
local page = frame.args[1] --"User:Jts1882/sandbox/test/Passeriformes"
local label = frame.args[1] or frame.args['label'] or frame.args['label1']
-- page , target tree, subtrees to exclude ...
-- page, include clade, multple clades to exclude |
return p._xlabel (frame, page, frame.args[2], frame.args[3], frame.args[4], frame.args[5])
end
p._xlabel = function (frame, page, target, ...)
-- local page = "User:Jts1882/sandbox/test/Passeriformes"
-- local label = frame.args[1] or frame.args['label']
local args = { ... }
local output = ""
if not args[1] then return p.errormsg ("Label name not provided") end
local fullOutput = p._label(frame, page, target)
--local fullOutput = p._section(frame, page, target)
output=fullOutput
local title = mw.title.new( mw.text.trim(page)) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title and title.exists then
local content = title:getContent()
for k,v in pairs(args) do
local section = mw.text.trim(v)
local targetType = "label%d"
local cladePrefix = "%d"
if string.upper( section) == section then
targetType = "target%u" -- by convention subtrees must be uppercase
cladePrefix = "subclade%u"
end
-- label = [[ name ]] |n= {...}
local pattern = "("..targetType.."=[%s%p]*"..section .. "[%s%p]*.-"..cladePrefix.."=.-)(%b{})"
-- ^^ this .- skips section tags before clade
-- ^^this .- skips |sublabel and styling following the label (but can return wrong clade when a subtree)
--for value in string.gmatch( fullOutput , pattern ) do
local value = string.match( fullOutput , pattern )
if value then
local trimmedTree, matches = string.gsub(fullOutput, pattern, "%1".."replacement string")--replaces pattern with capture %1
--output = output .. trimmedTree
--output = output .. "<pre>" .. trimmedTree .. "</pre>"
fullOutput = trimmedTree
else
output = output .. p.errormsg ("Failed to capture subclade with label "..section)
end
end
else
return '<span class="error">No page title found</span>'
end
if output ~= "" then
return frame:preprocess(fullOutput)
else
return '<span class="error">Section for label not found</span>'
end
end
--=============================== extract LABELS or SUBTREES=======================================
p.label = function (frame, page, ...)
local page = frame.args[1] --"User:Jts1882/sandbox/test/Passeriformes"
local label = frame.args[1] or frame.args['label'] or frame.args['label1']
local wrap = frame.args['wrap']
local output = p._label (frame, page, frame.args[2], frame.args[3], frame.args[4], frame.args[5] )
if wrap then
local label1 = string.lower(frame.args[2])
if wrap ~= "" then label1 = wrap end
output = "{{clade |label1=" .. p.firstToUpper(label1) .. "|1=" .. output .. "}}"
end
return frame:preprocess(output)
end
p._label = function (frame, page, ... )
-- local page = "User:Jts1882/sandbox/test/Passeriformes"
-- local label = frame.args[1] or frame.args['label']
local args = { ... }
local output = ""
if not args[1] then return p.errormsg ("Label name not provided") end
local title = mw.title.new( mw.text.trim(page)) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title and title.exists then
local content = title:getContent()
local targetType = "label%d"
local cladePrefix = "%d"
for k,v in pairs(args) do
local section = mw.text.trim(v)
if string.upper( section) == section then
targetType = "target%u" -- by convention subtrees must be uppercase
cladePrefix = "subclade%u"
end
-- label = [[ name ]] |n= {...}
--local pattern = "label%d=[%s%p]*"..section .. "[%s%p]*%d=(%b{})"
-- the .- skips section tags before clade
--local pattern = "label%d=[%s%p]*"..section .. "[%s%p]*%d=.-(%b{})"
-- this .- skips |sublabel and styling following the label (but can return wrong clade when a subtree)
--local pattern = "label%d=[%s%p]*"..section .. ".-%d=.-(%b{})"
local pattern = targetType.."=[%s%p]*"..section .. "[%s%p]*.-"..cladePrefix.."=.-(%b{})"
-- for subtrees (how to capture right )
--local pattern = "[%u]=[%s%p]*"..section .. ".-%d=.-(%b{})"
local value = string.match( content , pattern )
if value then
-- what if we have something like {FABIDS} "{%u}"
local pattern = "({%u-})"
if string.find(value, pattern ) then -- if a subtree that hasn't been substituted.
--local i,j,target = string.find(value, pattern) -- only one subtree
for target in string.gmatch( value , pattern ) do
local subtree = p._label (frame, page, target)
if subtree then
value = string.gsub(value, target, subtree)
end
--return value
--value = value .. " (subtree needs transcluding)"
end
end
--if (1==1) then return "Captured pattern=" .. (value or "no match") end
section = string.lower(section)
output = output .. value
--output = output .. "{{clade |label1=" .. p.firstToUpper(section) .. "|1=" .. value .. "}}"
else
output = output .. p.errormsg ("Failed to capture subclade with label "..section)
end
end
else
return '<span class="error">No page title found</span>'
end
if output ~= "" then
--return frame:preprocess(output)
return output -- preprocess in entry function
else
return '<span class="error">Section for label not found</span>'
end
end
p.section = function (frame)
-------------------------target page ---- sections
return frame:preprocess(p._section(frame, mw.text.trim(frame.args[1]),frame.args[2],frame.args[3],frame.args[4],frame.args[5]))
end
p._section = function (frame,page,...)
local args = { ... }
local output = ""
local title = mw.title.new( page) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title and title.exists then
local content = title:getContent()
content = string.gsub( content , "%<%!%-%-.-%-%-%>", "" ) -- strip out comments
for k,v in pairs(args) do
local section = mw.text.trim(v)
--[[ note: using the non-greedy - in (.-) to allow capture of several sections
this allows internal clade structures to be closed without capturing sisters clades
e.g. see section Tyranni in User:Jts1882/sandbox/test/Passeriformes
]]
local pattern = "<section begin="..section.."[ ]*/>(.-)<section end="..section.."[ ]*/>"
for value in string.gmatch( content , pattern ) do
if value then
if frame.args.wrap or frame:getParent().args.wrap then
local label1 = frame.args.wrap or frame:getParent().args.wrap
if label1 == "" then label1 = section end
value = "{{clade |label1=" .. label1 .. "|1=" .. value .. "}}"
end
output = output .. value
end
end
end
else
return '<span class="error">No page title found</span>'
end
if output ~= "" then
--return frame:preprocess(output)
return output -- leave preprocessing for entry function
else
return '<span class="error">Section not found</span>'
end
end
p.xsection = function (frame)
local page = frame.args[1] --"User:Jts1882/sandbox/test/Passeriformes"
local label = frame.args[1] or frame.args['label'] or frame.args['label1']
-- page , target tree, sections to exclude ...
return frame:preprocess(p._xsection(frame, page ,frame.args[2],frame.args[3],frame.args[4],frame.args[5]))
end
p._xsection = function (frame,page, target, ...)
local args = { ... }
local output = ""
local title = mw.title.new( page) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title and title.exists then
local content = title:getContent()
local fullOutput = p._section(frame, page, target)
output=fullOutput
for k,v in pairs(args) do
local section = mw.text.trim(v)
--[[ note: using the non-greedy - in (.-) to allow capture of several sections
this allows internal clade structures to be closed without capturing sisters clades
e.g. see section Tyranni in User:Jts1882/sandbox/test/Passeriformes
]]
local pattern = "(<section begin="..section.."[ ]*/>)(.-)(<section end="..section.."[ ]*/>)"
local value = string.match( fullOutput , pattern )
if value then
local trimmedTree, matches = string.gsub(fullOutput, pattern, "replacement string")--replaces pattern with capture %1
output = output .. trimmedTree
output = output .. "<pre>" .. trimmedTree .. "</pre>"
fullOutput = trimmedTree
else
output = output .. p.errormsg ("Failed to capture subclade with label "..section)
end
end
else
return '<span class="error">No page title found</span>'
end
if output ~= "" then
--return frame:preprocess(output)
return output -- leave preprocessing for entry function
else
return '<span class="error">Section not found</span>'
end
end
function p.populations(frame)
local args = frame.args
local page = "List of countries by population (United Nations)"
local output = ""
local data = {}
local total = 0
local totalProjected = 0
local count = 0
local title = mw.title.new( page) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title and title.exists then
local content = title:getContent()
local pattern = "<section begin=date_1[ ]*/>(.-)<section end=date_1[ ]*/>"
for value in string.gmatch( content , pattern ) do
data['date']=value -- date of latest data
end
local pattern = "<section begin=date_0[ ]*/>(.-)<section end=date_0[ ]*/>"
for value in string.gmatch( content , pattern ) do
data['date2']=value -- date of previous data
data['date2']=mw.getContentLanguage():formatDate('j F Y', value)
end
data['today'] = mw.getContentLanguage():formatDate('j F Y') -- today's date (for formatting see https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time)
local ay = (frame:callParserFunction{ name = '#time', args = { "U", data['today'] } }
- frame:callParserFunction{ name = '#time', args = { "U", data['date2'] } })
/60/60/24/365.2425 -- number of years since first date until today
for k,v in pairs(args) do
local country = mw.text.trim(v)
-- get population data from section
local section = country .. "_1"
local pattern = "<section begin="..section.."[ ]*/>(.-)<section end="..section.."[ ]*/>"
for value in string.gmatch( content , pattern ) do
if value then
count=count+1
data[count] = {}
data[count]['country'] = country
data[count]['populationString'] = frame:preprocess(value)
local raw = string.gsub(data[count]['populationString'], ",", "") -- strip formatting from number string
data[count]['populationNumber'] = tonumber(raw)
total = total + data[count]['populationNumber']
local section = country .. "_0"
local pattern2 = "<section begin="..section.."[ ]*/>(.-)<section end="..section.."[ ]*/>"
for value2 in string.gmatch( content , pattern2 ) do
data[count]['populationString2'] = frame:preprocess(value2)
local raw = string.gsub(data[count]['populationString2'], ",", "") -- strip formatting from number string
data[count]['populationNumber2'] = tonumber(raw)
data[count]['populationIncrement']=data[count]['populationNumber'] - data[count]['populationNumber2']
data[count]['populationGrowth'] =data[count]['populationIncrement']/data[count]['populationNumber2']
data[count]['populationDouble'] = math.log( 2 ) / math.log(1 + data[count]['populationGrowth'])
data[count]['populationProjected'] = math.pow(data[count]['populationNumber2'], 1 - ay )
* math.pow(data[count]['populationNumber'], ay)
totalProjected = totalProjected + data[count]['populationProjected']
end
end
end
end
local sort_function = function( a,b )
if (tonumber(a.populationNumber) > tonumber(b.populationNumber)) then -- primary sort on 'population' -> a before b
return true
end
end
local test = "test: "
local number=5435.12345
test= fn.formatNum(5435.12345,"en",0)
--test= frame:expandTemplate{ title = "formatnum", args = { totalProjected ,"en",0 } }
--test=frame:callParserFunction{ name = 'formatnum', args = { totalProjected, decs=2 } }
table.sort(data, sort_function)
local i = 1
-- output table
output = '{| class="wikitable sortable" style="text-align:right;" '
.. '\n!rowspan=2|#'
.. '\n!rowspan=2|Country'
.. '\n!rowspan=2|Projected population<br/>(' .. data['today'] .. ')'
.. '\n!rowspan=2|Pct of total'
.. '\n!rowspan=2|Population<br/>(' .. data['date'] .. ')'
--.. '\n!rowspan=2|Pct of total'
.. '\n!rowspan=2|Previous Population<br/>(' .. data['date2'] .. ')'
.. '\n!colspan=2|Annual growth'
.. '\n!rowspan=2|Doubling time<br/>(years)'
.. '\n|-\n!Increment'
.. '\n!Rate'
while (data[i]) do
output = output .. '\n|-\n|' .. i
output = output .. '\n|style="text-align:left;" |' .. frame:expandTemplate{ title = "flagcountry", args = {data[i]['country'] } }
output = output .. '\n| ' .. mm._precision_format(data[i]['populationProjected'],0)
--output = output .. '\n| ' .. fn.formatNum(data[i]['populationProjected'],"en",0)
output = output .. '\n| ' .. mm._precision_format(data[i]['populationProjected']/totalProjected*100,2) .. "%" -- projected
output = output .. '\n| ' .. data[i]['populationString']
--output = output .. '\n| ' .. fn.formatNum(data[i]['populationNumber']/total*100,"en",2) .. "%"
output = output .. '\n| ' .. data[i]['populationString2']
output = output .. '\n| ' .. mm._precision_format(data[i]['populationIncrement'],0)
output = output .. '\n| ' .. mm._round(data[i]['populationGrowth']*100,2) .. "%"
output = output .. '\n| ' .. mm._round(data[i]['populationDouble'],0)
i=i+1
end
output = output .. '\n|-\n! !! Total'
.. '\n! style="text-align:right;" |' .. fn.formatNum(mm._round(totalProjected,0),"en",0)
.. '\n! style="text-align:right;" | 100% '
.. '\n! style="text-align:right;" |' .. fn.formatNum(total,"en",0)
--.. '\n! style="text-align:right;" | 100% '
.. '\n! || || ||' -- ..test
output = output .. '\n|}'
else
return '<span class="error">No page title found</span>'
end
return output
end
function p.firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
p.errormsg = function (message)
return '<span class="error">' .. message .. '</span>'
end
return p