ମଡ୍ୟୁଲ:Autotaxobox/sandbox
Documentation for this module may be created at ମଡ୍ୟୁଲ:Autotaxobox/sandbox/doc
--[[
This module provides support to the automated taxobox system – the templates
Automatic taxobox, Speciesbox, Subspeciesbox, Infraspeciesbox, etc.
In particular it provides a way of traversing the taxonomic hierarchy encoded
in taxonomy templates (templates with names of the form
"Template:Taxonomy/TAXON_NAME") without causing template expansion depth errors.
]]
local p = {}
--[[=========================================================================
Limit the maximum depth of a taxonomic hierarchy that can be traversed;
avoids excessive processing time and protects against incorrectly set up
hierarchies, e.g. loops.
=============================================================================]]
local MaxSearchLevels = 100
function p.getMaxSearchLevels()
return MaxSearchLevels
end
--[[========================== taxoboxColour ================================
Determines the correct colour for a taxobox, by searching up the taxonomic
hierarchy from the supplied taxon for the first taxon (other than
'incertae sedis') that sets a taxobox colour. It is assumed that a valid
taxobox colour is defined using CSS rgb() syntax.
If no taxon that sets a taxobox colour is found, then 'transparent' is
returned unless the taxonomic hierarchy is too deep, when the error colour is
returned.
Usage: {{#invoke:Autotaxobox|taxoboxColour|TAXON}}
=============================================================================]]
function p.taxoboxColour(frame)
local currTaxon = frame.args[1]
local i = 1 -- count levels processed
local searching = currTaxon ~= '' -- still searching for a colour?
local foundICTaxon = false -- record whether 'incertae sedis' found
local colour = '' -- default is no colour
while searching and i < MaxSearchLevels do
local plainCurrTaxon = p.stripExtra(currTaxon) -- remove trailing text after /
if string.lower(plainCurrTaxon) == 'incertae sedis' then
foundICTaxon = true
else
local possibleColour = frame:expandTemplate{ title = 'Template:Taxobox colour', args = { plainCurrTaxon } }
if string.sub(possibleColour,1,3) == 'rgb' then
colour = possibleColour
searching = false
end
end
if searching then
local ok, parent = pcall(frame.expandTemplate, frame, { title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } })
if ok and parent ~= '' then
currTaxon = parent
i = i + 1
else
searching = false -- run off the top of the hierarchy or tried to use non-existent taxonomy template
end
end
end
if colour ~= '' then
return colour
elseif foundICTaxon then
return frame:expandTemplate{ title = 'Template:Taxobox colour', args = { 'incertae sedis' } }
elseif searching then
-- hierarchy exceeds MaxSearchLevels levels
return frame:expandTemplate{ title = 'Template:Taxobox/Error colour', args = { } }
else
return 'transparent'
end
end
--[[=========================== taxoboxList =================================
Displays the rows of taxa in an automated taxobox, based on the taxonomic
hierarchy for the supplied taxon.
Usage:
{{#invoke:Autotaxobox|taxoboxList|TAXON
|display_taxa = the number of taxa *above* TAXON to force to be displayed
|authority = taxonomic authority for TAXON
|parent_authority = taxonomic authority for TAXON's parent
|gparent_authority = taxonomic authority for TAXON's grandparent
|ggparent_authority = taxonomic authority for TAXON's greatgrandparent
|ggparent_authority = taxonomic authority for TAXON's greatgreatgrandparent
|bold_first = 'bold' to bold TAXON in its row
}}
=============================================================================]]
function p.taxoboxList(frame)
local currTaxon = frame.args[1]
local displayN = (tonumber(frame.args['display_taxa']) or 1) + 1
local auth = frame.args['authority'] or ''
local parentAuth = frame.args['parent_authority'] or ''
local gParentAuth = frame.args['gparent_authority'] or ''
local ggParentAuth = frame.args['ggparent_authority'] or ''
local gggParentAuth = frame.args['gggparent_authority'] or ''
local boldFirst = frame.args['bold_first'] or 'link' -- values 'link' or 'bold'
local taxonTable = p.makeTable(frame, currTaxon)
local res = ''
-- display all taxa above possible greatgreatgrandparent
for i = taxonTable.n, 6, -1 do
res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[i], fc = tostring(displayN >= i) } }
end
-- display greatgreatgrandparent, if it exists
if taxonTable.n >= 5 then
lres = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[5], authority = gggParentAuth, fc = tostring(displayN >= 5) } }
end
-- display greatgrandparent, if it exists; force the display if an infrataxon is below
if taxonTable.n >= 4 then
local force = tostring(displayN >= 4) or
frame.expandTemplate{ title = 'Template:Infrataxon()', args = { taxonTable[3] } } == 'true' or
frame.expandTemplate{ title = 'Template:Infrataxon()', args = { taxonTable[2] } } == 'true'
res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[4], authority = ggParentAuth, fc = tostring(force) } }
end
-- display grandparent, if it exists; force the display if an infrataxon is below
if taxonTable.n >= 3 then
local force = tostring(displayN >= 3) or
frame.expandTemplate{ title = 'Template:Infrataxon()', args = { taxonTable[2] } } == 'true'
res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[3], authority = gParentAuth, fc = tostring(force) } }
end
-- display parent, if it exists
if taxonTable.n >= 2 then
res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[2], authority = parentAuth, fc = tostring(displayN >= 2) } }
end
-- display target taxon
res = res .. frame:expandTemplate{ title = 'Template:Taxobox/showtaxon', args = { taxonTable[1], authority = auth, fc = 'true', format = boldFirst } }
return res
end
--[[========================== taxonomyList =================================
Returns the cells of the taxonomy table displayed on "Template:Taxonomy...."
pages.
Usage: {{#invoke:Autotaxobox|taxonomyList|TAXON}}
=============================================================================]]
function p.taxonomyList(frame)
local currTaxon = frame.args[1]
if currTaxon == '' then return 'ERROR: no taxon supplied' end
local taxonTable = p.makeTable(frame, currTaxon)
local rankTable = p.getRankTable()
local lastRankVal = 1000000
local orderOk
local res = ''
for i = taxonTable.n, 1, -1 do
local rank = frame:expandTemplate{ title = 'Template:Taxonomy/' .. taxonTable[i], args = {['machine code'] = 'rank' } }
local currRankVal = rankTable[rank]
if currRankVal then
orderOk = currRankVal < lastRankVal
if orderOk then lastRankVal = currRankVal end
else
orderOk = true
end
if orderOk then
res = res .. frame:expandTemplate{ title = 'Template:Taxonomy links', args = { taxonTable[i] } }
else
res = res .. frame:expandTemplate{ title = 'Template:Taxonomy links', args = { taxonTable[i], error = 'true' } }
end
end
return res
end
--[[=============================== nth =====================================
External utility function primarily intended for use in checking and debugging.
Returns the nth level above a taxon in a taxonomic hierarchy, where the taxon
itself is counted as the first level.
Usage: {{#invoke:Autotaxobox|nth|TAXON|n=N}}
=============================================================================]]
function p.nth(frame)
local currTaxon = frame.args[1]
if currTaxon == '' then return 'ERROR: no taxon supplied' end
local n = tonumber(frame.args['n'])
if n > MaxSearchLevels then return 'Exceeded maximum number of levels allowed (' .. MaxSearchLevels .. ')' end
local i = 1
local inHierarchy = true -- still in the taxonomic hierarchy or off the top?
while i < n and inHierarchy do
local parent = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } }
if parent ~= '' then
currTaxon = parent
i = i + 1
else
inHierarchy = false
end
end
if inHierarchy then return currTaxon
else return 'Level ' .. n .. ' is past the top of the taxonomic hierarchy'
end
end
--[[============================= nLevels ===================================
External utility function primarily intended for use in checking and debugging.
Returns number of levels in a taxonomic hierarchy, starting from
the supplied taxon as level 1.
Usage: {{#invoke:Autotaxobox|nLevels|TAXON}}
=============================================================================]]
function p.nLevels(frame)
local currTaxon = frame.args[1]
if currTaxon == '' then return 'ERROR: no taxon supplied' end
local i = 1
local inHierarchy = true -- still in the taxonomic hierarchy or off the top?
while inHierarchy and i < MaxSearchLevels do
local parent = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } }
if parent ~= '' then
currTaxon = parent
i = i + 1
else
inHierarchy = false
end
end
if inHierarchy then return MaxSearchLevels .. '+'
else return i
end
end
--[[============================= listAll ===================================
External utility function primarily intended for use in checking and debugging.
Returns a comma separated list of a taxonomic hierarchy, starting from
the supplied taxon.
Usage: {{#invoke:Autotaxobox|listAll|TAXON}}
=============================================================================]]
function p.listAll(frame)
local currTaxon = frame.args[1]
if currTaxon == '' then return 'ERROR: no taxon supplied' end
return p.listTaxa(p.makeTable(frame, currTaxon))
end
--[[=========================================================================
Internal functions
=============================================================================]]
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Internal utility function to strip off any extra parts of a taxon name, i.e.
anything after a '/'. Thus "Felidae/?" would be reduced to "Felidae".
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function p.stripExtra(taxonName)
local i = string.find(taxonName,'/')
if i then
return string.sub(taxonName,1,i-1)
else
return taxonName
end
end
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Internal utility function to convert a taxon table to a comma-separated list.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function p.listTaxa(taxonTable)
local lst = taxonTable[1]
for i = 2, taxonTable.n, 1 do
lst = lst .. ', ' .. taxonTable[i]
end
return lst
end
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Internal utility function to return a table (array) constructed from a
taxonomic hierarchy stored in "Template:Taxonomy/..." templates.
TABLE.n holds the total number of taxa; TABLE[1]..TABLE[TABLE.n] the taxon
names.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function p.makeTable(frame, currTaxon)
local i = 1
local inHierarchy = true -- still in the taxonomic hierarchy or off the top?
local taxonTable = {}
taxonTable[1] = currTaxon;
while i < MaxSearchLevels and inHierarchy do
local ok, parent = pcall(frame.expandTemplate, frame, { title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } })
if ok and parent ~= '' then
currTaxon = parent
i = i + 1
taxonTable[i] = currTaxon
else
inHierarchy = false -- run off the top of the hierarchy or tried to use non-existent taxonomy template
end
end
taxonTable.n = i
return taxonTable
end
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Internal utility function to set up a table of numerical values corresponding
to 'Linnaean' ranks, with upper ranks having higher values. In a valid
taxonomic hierarchy, a lower rank should never have a higher value than a
higher rank. The actual numerical values are arbitrary so long as they are
ordered.
The ranks should correspond to those in Template:Anglicise ranks.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function p.getRankTable()
return {
classis = 1400,
cohort = 1100,
divisio = 1500,
domain = 1700,
familia = 800,
genus = 600,
grandordo = 1030,
infraclassis = 1370,
infralegio = 1170,
infraordo = 970,
infraphylum = 1470,
infraregnum = 1570,
infratribus = 670,
legio = 1200,
magnordo = 1040,
micrordo = 960,
mirordo = 1020,
nanordo = 990,
ordo = 1000,
parafamilia = 799,
parvordo = 970,
phylum = 1500,
regnum = 1600,
sectio = 500,
series = 400,
species = 300,
subclassis = 1380,
subcohort = 1080,
subdivisio = 1480,
subfamilia = 780,
subgenus = 580,
sublegio = 1180,
subordo = 980,
subphylum = 1480,
subregnum = 1580,
subsectio = 480,
subspecies = 280,
subtribus = 680,
superclassis = 1410,
supercohort = 1110,
superdivisio = 1510,
superdomain = 1710,
superfamilia = 810,
superlegio = 1210,
superordo = 1010,
superphylum = 1510,
superregnum = 1610,
supertribus = 710,
tribus = 700,
varietas = 200,
zoodivisio = 1300,
zoosectio = 900,
zoosubdivisio = 1280,
zoosubsectio = 880
}
end
--[[=========================== SANDBOX ONLY ================================
]]
--[[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =]]
function p.getTaxonInfo(frame)
local currTaxon = frame.args[1]
if currTaxon == '' then return 'ERROR: no taxon supplied' end
local infoStr = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'all' } }
local info = mw.text.split(infoStr, '$', true)
if info[7] ~= '' then
local sameAsInfoStr = frame:expandTemplate{ title = 'Template:Taxonomy/' .. info[7], args = {['machine code'] = 'all' } }
local sameAsInfo = mw.text.split(sameAsInfoStr, '$', true)
for i = 1,6,1 do
if info[i] == '' then info[i] = sameAsInfo[i] end
end
end
--return information
local res = 'parent='..info[1]..'; rank='..info[2]..'; link='..info[3]..'; link text='..info[4]..
'; always displayed='..info[5]..'; extinct='..info[6]..'; same as='..info[7]
return res
end
function p.chkRanks(frame)
local currTaxon = frame.args[1]
if currTaxon == '' then return 'ERROR: no taxon supplied' end
local taxonTable = p.makeTable(frame, currTaxon)
local rankTable = p.getRankTable()
local res = ''
local lastRankVal = -1
for i = 1,taxonTable.n,1 do
local rank = frame:expandTemplate{ title = 'Template:Taxonomy/' .. taxonTable[i], args = {['machine code'] = 'rank' } }
local currRankVal = rankTable[rank]
if currRankVal then
--res = res .. rank .. '=' .. currRankVal .. ', '
if currRankVal <= lastRankVal then res = res .. 'ERROR: ranks out of order at ' .. taxonTable[i] ..
', rank = ' .. rank .. '\n'
end
lastRankVal = currRankVal
end
end
return res
end
return p