Module:eFloras

From Stiles Wiki
Jump to navigation Jump to search


Usage

This module performs tasks for Template:eFloras. The first task is taking the flora_id and the name of the family (or tribe of Asteraceae) and converting them to the corresponding volume numbers for the Floras of North America, China, and Chile. The second is taking the flora_id from the URL and returning the corresponding flora or list name. The data used for these two tasks is in Module:eFloras/data. The third is detecting what type of scientific name is in the third parameter of the template, and applying the correct italicization. For this purpose, the module strips initial and final whitespace, and any italicization or bolding.

{{#invoke:EFloras|volume|1|family=Rosaceae}} or {{#invoke:EFloras|volume|1|Rosaceae}}
{{#invoke:EFloras|resource|1}}
{{#invoke:eFloras|volumeDate|1||Rosaceae}}
{{#invoke:eFloras|volumeDate|1|9|}}
{{#invoke:eFloras|volumeName|1||Rosaceae}}
{{#invoke:eFloras|volumeName|1|9|}}
  • 9
  • Flora of North America North of Mexico (FNA)
  • 2014
  • 2014
  • Magnoliophyta: Picramniaceae to Rosaceae
  • Magnoliophyta: Picramniaceae to Rosaceae


  • {{#invoke:eFloras|name|Asteraceae}}
Asteraceae
  • {{#invoke:eFloras|name|Aster}}
Aster
  • {{#invoke:eFloras|name|Aster ericoides}}
Aster ericoides
  • {{#invoke:eFloras|name|Aster ericoides var. ericoides}}
Aster ericoides var. ericoides
  • {{#invoke:eFloras|name|Aster ericoides'' var. ''ericoides}}
Aster ericoides var. ericoides
  • {{#invoke:eFloras|name|Acer tataricum subsp. ginnala}}
Acer tataricum subsp. ginnala



require('Module:No globals')

local p = {}

local data -- Load [[Module:eFloras/data]] if needed and assign to this variable.

local function getResource(floraID)
	data = data or mw.loadData("Module:eFloras/data")
	return data.resources[floraID] or data.resources[tonumber(floraID)]
end

function p.resource(frame)
	local floraID = string.match(frame.args[1], "%d+")
	if floraID == nil then
		return "<span style=\"color: red;\">Please provide a resource number (<code>flora_id</code>). See the list of supported resource numbers at [[Module:eFloras/doc]]</span>"
	else
		local familyToVolume = getResource(floraID)
		if familyToVolume == nil then
			return "<span style=\"color: red;\">The resource number (<code>flora_id</code>) <code>" .. floraID .. "</code> is not recognized. See the list of supported resource numbers at [[Module:eFloras/doc]]</span>[[Category:Pages using eFloras template with unsupported parameter values]]"
		else
			return familyToVolume
		end
	end
end

function p._volumeName(floraID, volume, family)
	floraID = tonumber(floraID)
	
	if not floraID then -- floraID is not a number.
		return
	end
	
	data = data or mw.loadData("Module:eFloras/data")
	
	if not volume then
		local familyToVolume = data.volumeTable[floraID]
		if not familyToVolume then
			return
		end
		
		volume = tonumber(familyToVolume[family])
	
		if not volume then
			return
		end
	end
	
	local floraVolumeNames = data.volumeNames and data.volumeNames[floraID]
	if floraVolumeNames and volume then
		return floraVolumeNames[volume]
	end
end

function p.volumeName(frame)
	if not (frame.args[1] and (frame.args[2] or frame.args[3] or frame.args.family)) then
		return
	end
	
	local floraID = string.match(frame.args[1], "%d+")
	local volume = tonumber(frame.args[2])
	local family = frame.args[3] or frame.args.family
	
	if not (floraID and (volume or family)) then
		return
	end
	
	return p._volumeName(floraID, volume, family)
end

function p._volumeDate(floraID, volume, family)
	floraID = tonumber(floraID)
	
	if not floraID then -- floraID is not a number.
		return
	end
	
	data = data or mw.loadData("Module:eFloras/data")
	
	if not volume then
		local familyToVolume = data.volumeTable[floraID]
		if not familyToVolume then
			return
		end
		
		volume = tonumber(familyToVolume[family])
	
		if not volume then
			return
		end
	end
	
	local floraVolumeDates = data.volumeDates and data.volumeDates[floraID]
	if floraVolumeDates then
		if volume and floraVolumeDates[volume] then
			return floraVolumeDates[volume]
		else
			return floraVolumeDates.default
		end
	end
end

function p.volumeDate(frame)
	if not (frame.args[1] and (frame.args[2] or frame.args[3] or frame.args.family)) then
		return
	end
	
	local floraID = string.match(frame.args[1], "%d+")
	local volume = tonumber(frame.args[2])
	local family = frame.args[3] or frame.args.family
	
	if not (floraID and (volume or family)) then
		return
	end
	
	return p._volumeDate(floraID, volume, family)
end

function p.volume(frame)
	local floraID = string.match(frame.args[1], "%d+")
	local family = frame.args[2] or frame.args.family
	data = data or mw.loadData("Module:eFloras/data")
	local familyToVolume = data.volumeTable[floraID] or data.volumeTable[tonumber(floraID)]
	if familyToVolume == nil then
		return ""
	else
		local volume = familyToVolume[family]
		if volume == "error" then
			return "19&ndash;21 [[Category:Pages using eFloras template with unsupported parameter values]]"
		elseif volume == nil then
			return ""
		else
			return volume
		end
	end
end

-- Italicize if name requires it.
function p.italicize(name)
	local orig = name
	name = string.gsub(name, "^%s*(.-)%s*$", "%1")
	
	local count
	name, count = string.gsub(name, "\'\'\'?", "")
	
	if count > 0 then
		-- A tracking method used on Wiktionary: [[wikt:Module:debug]].
		-- To see the results:
		-- [[Special:WhatLinksHere/Template:tracking/eFloras/italics or bolding]]
		local frame = mw.getCurrentFrame()
		pcall(frame.expandTemplate, frame, { title = 'tracking/eFloras/italics or bolding' })
		mw.log("Italics in input to the italicize function in Module:eFloras:", orig)
	end
	
	local rank
	local lowerName = name:lower()
	if name == "" or name == nil then
		return
	elseif string.find(name, "^%u%l+ae$") then
		if string.find(name, "eae$") then
			if string.find(name, "aceae$") then
				rank = "family"
			elseif string.find(name, "oideae$") then
				rank = "subfamily"
			else
				rank = "tribe"
			end
		elseif string.find(name, "inae$") then
			rank = "subtribe"
		end
	elseif string.find(lowerName, "subsp.", 1, true) then
		rank = "subspecies"
	elseif string.find(lowerName, "subg.", 1, true) then
		rank = "subgenus"
	elseif string.find(lowerName, "var.", 1, true) then
		rank = "variety"
	elseif string.find(lowerName, "sect.", 1, true) then
		rank = "section"
	elseif string.find(name, "^%a+%s[%a-]+$") or string.find(name, "^%a+%s×%s[%a-]+$") then
		rank = "species"
	elseif string.find(name, "^%u%a+$") -- No one-letter genera, probably.
			and not string.find(name, ".%u") then -- Uppercase letters can only appear at beginning of taxonomic name.
		rank = "genus"
	end
	
	if not rank then
		mw.log("Module:eFloras could not determine a taxonomic rank for the input that it received: " .. name)
		return orig
	end
	
	if rank == "genus" or rank == "subgenus" or rank == "species"
			or rank == "subspecies" or rank == "variety" or rank == "section" then
		
		name = "<i>" .. name .. "</i>"
		local hybrid = "×"
		
		if name:find(".", 1, true) then
			local abbreviations = {
				["subsp."] = true, ["ssp."] = true, ["var."] = true, ["f."] = true,
				["sect."] = true, ["subsect."] = true, ["subg."] = true,
			}
			
			local unrecognized
			name = name:gsub(
				"%s+(%S+%.)%s+",
				function (abbreviation)
					mw.log(name, abbreviation, abbreviation:lower(), abbreviations[abbreviation:lower()])
					if abbreviations[abbreviation:lower()] then
						return "</i> " .. abbreviation .. " <i>"
					else
						unrecognized = unrecognized or {}
						table.insert(unrecognized, abbreviation)
					end
				end)
			
			if unrecognized then
				mw.log(string.format("The abbreviation%s %s %s not recognized.",
					unrecognized[2] and "s" or "",
					table.concat(
						unrecognized,
						", "),
					unrecognized[2] and "are" or "is"))
				return orig
			end
		end
		
		name = name:gsub("%s+" .. hybrid .. "%s+", "</i> " .. hybrid .. " <i>")
	end -- Else do not modify name.
	
	return name
end

function p.name(frame)
	local name = frame.args[1]
	return p.italicize(name)
end 

p.get_volume = p.volume

return p