Module:User:Theknightwho/families

Hello, you have come here looking for the meaning of the word Module:User:Theknightwho/families. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:User:Theknightwho/families, but we will also tell you about its etymology, its characteristics and you will know how to say Module:User:Theknightwho/families in singular and plural. Everything you need to know about the word Module:User:Theknightwho/families you have here. The definition of the word Module:User:Theknightwho/families will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:User:Theknightwho/families, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.


local insert = table.insert
local load_data = mw.loadData

local export = {}

local function conditionalRequire(modname, useRequire)
	return (useRequire and require or load_data)(modname)
end

local Family = {}

--==]
function Family:getFamily()
	if self._familyObject == nil then
		local familyCode = self:getFamilyCode()
		if familyCode then
			self._familyObject = export.getByCode(familyCode, useRequire)
		else
			self._familyObject = false
		end
	end
	return self._familyObject or nil
end

--==]
function Family:getFamilyCode()
	if not self._familyCode then
		self._familyCode = self._rawData
	end
	return self._familyCode
end

--==]
function Family:getFamilyName()
	if self._familyName == nil then
		local family = self:getFamily()
		if family then
			self._familyName = family:getCanonicalName()
		else
			self._familyName = false
		end
	end
	return self._familyName or nil
end

--==]
function Family:inFamily(...)
	for _, superfamily in ipairs{...} do
		if type(superfamily) == "table" then
			superfamily = superfamily:getCode()
		end
		local family, code = self:getFamily()
		while true do
			if not family then
				return false
			end
			code = family:getCode()
			family = family:getFamily()
			-- If family is parent to itself, return false.
			if family and family:getCode() == code then
				return false
			elseif code == superfamily then
				return true
			end
		end
	end
end

function Family:getParent()
	if self._parentObject == nil then
		local parentCode = self:getParentCode()
		if parentCode then
			self._parentObject = require("Module:languages").getByCode(parentCode, nil, true, true, useRequire)
		else
			self._parentObject = false
		end
	end
	return self._parentObject or nil
end

function Family:getParentCode()
	if not self._parentCode then
		self._parentCode = self._rawData
	end
	return self._parentCode
end

function Family:getParentName()
	if self._parentName == nil then
		local parent = self:getParent()
		if parent then
			self._parentName = parent:getCanonicalName()
		else
			self._parentName = false
		end
	end
	return self._parentName or nil
end

function Family:getParentChain()
	if not self._parentChain then
		self._parentChain = {}
		local parent = self:getParent()
		while parent do
			insert(self._parentChain, parent)
			parent = parent:getParent()
		end
	end
	return self._parentChain
end

function Family:hasParent(...)
	--checkObject("family", nil, ...)
	for _, other_family in ipairs{...} do
		for _, parent in ipairs(self:getParentChain()) do
			if type(other_family) == "string" then
				if other_family == parent:getCode() then return true end
			else
				if other_family:getCode() == parent:getCode() then return true end
			end
		end
	end
	return false
end

--[==[
If the family is etymology-only, this iterates through its parents until a full family is found, and the
corresponding object is returned. If the family is a full family, then it simply returns itself.
]==]
function Family:getFull()
	if not self._fullObject then
		local fullCode = self:getFullCode()
		if fullCode ~= self:getCode() then
			self._fullObject = require("Module:languages").getByCode(fullCode, nil, nil, true, useRequire)
		else
			self._fullObject = self
		end
	end
	return self._fullObject
end

--[==[
If the family is etymology-only, this iterates through its parents until a full family is found, and the
corresponding code is returned. If the family is a full family, then it simply returns the family code.
]==]
function Family:getFullCode()
	return self._fullCode or self:getCode()
end

--[==[
If the family is etymology-only, this iterates through its parents until a full family is found, and the
corresponding canonical name is returned. If the family is a full family, then it simply returns the canonical name
of the family.
]==]
function Family:getFullName()
	if self._fullName == nil then
		local full = self:getFull()
		if full then
			self._fullName = full:getCanonicalName()
		else
			self._fullName = false
		end
	end
	return self._fullName or nil
end

--[==[
Return a {Language} object (see ]) for the proto-language of this family, if one exists.
Otherwise, return {nil}.
]==]
function Family:getProtoLanguage()
	if self._protoLanguageObject == nil then
		self._protoLanguageObject = require("Module:languages").getByCode(self._rawData.protoLanguage or self:getCode() .. "-pro", nil, true, nil, useRequire) or false
	end
	return self._protoLanguageObject or nil
end

function Family:getProtoLanguageCode()
	if self._protoLanguageCode == nil then
		local protoLanguage = self:getProtoLanguage()
		self._protoLanguageCode = protoLanguage and protoLanguage:getCode() or false
	end
	return self._protoLanguageCode or nil
end

function Family:getProtoLanguageName()
	if not self._protoLanguageName then
		self._protoLanguageName = self:getProtoLanguage():getCanonicalName()
	end
	return self._protoLanguageName
end

function Family:hasAncestor(...)
	-- Go up the family tree until a protolanguage is found.
	local family = self
	local protolang = family:getProtoLanguage()
	while not protolang do
		family = family:getFamily()
		protolang = family:getProtoLanguage()
		-- Return false if the family is its own family, to avoid an infinite loop.
		if family:getFamilyCode() == family:getCode() then
			return false
		end
	end
	-- If the protolanguage is not in the family, it must therefore be ancestral to it. Check if it is a match.
	for _, otherlang in ipairs{...} do
		if (
			type(otherlang) == "string" and protolang:getCode() == otherlang or
			type(otherlang) == "table" and protolang:getCode() == otherlang:getCode()
		) and not protolang:inFamily(self) then
			return true
		end
	end
	-- If not, check the protolanguage's ancestry.
	return protolang:hasAncestor(...)
end

local function fetch_descendants(self, format)
	local languages = require("Module:languages/code to canonical name")
	local etymology_languages = require("Module:etymology languages/code to canonical name")
	local families = require("Module:families/code to canonical name")
	local descendants = {}
	-- Iterate over all three datasets.
	for _, data in ipairs{languages, etymology_languages, families} do
		for code in pairs(data) do
			local lang = require("Module:languages").getByCode(code, nil, true, true, useRequire)
			if lang:inFamily(self) then
				if format == "object" then
					insert(descendants, lang)
				elseif format == "code" then
					insert(descendants, code)
				elseif format == "name" then
					insert(descendants, lang:getCanonicalName())
				end
			end
		end
	end
	return descendants
end

function Family:getDescendants()
	if not self._descendantObjects then
		self._descendantObjects = fetch_descendants(self, "object")
	end
	return self._descendantObjects
end

function Family:getDescendantCodes()
	if not self._descendantCodes then
		self._descendantCodes = fetch_descendants(self, "code")
	end
	return self._descendantCodes
end

function Family:getDescendantNames()
	if not self._descendantNames then
		self._descendantNames = fetch_descendants(self, "name")
	end
	return self._descendantNames
end

function Family:hasDescendant(...)
	for _, lang in ipairs{...} do
		if type(lang) == "string" then
			lang = require("Module:languages").getByCode(lang, nil, true, nil, useRequire)
		end
		if lang:inFamily(self) then
			return true
		end
	end
	return false
end

--[==[
Return the name of the main category of that family. Example: {"Germanic languages"} for the Germanic languages,
whose category is at ].

Unless optional argument `nocap` is given, the family name at the beginning of the returned value will be
capitalized. This capitalization is correct for category names, but not if the family name is lowercase and
the returned value of this function is used in the middle of a sentence. (For example, the pseudo-family with
the code {qfa-mix} has the name {"mixed"}, which should remain lowercase when used as part of the category name
] but should be capitalized in ].)
If you are considering using {getCategoryName("nocap")}, use {getDisplayForm()} instead.
]==]
function Family:getCategoryName(nocap)
	local name = self._rawData

	-- If the name already ends with "languages" or "lects", don't add it.
	if not (name:match("anguages$") or name:match("ects$")) then
		name = name .. " languages"
	end
	if not nocap then
		name = mw.getContentLanguage():ucfirst(name)
	end
	return name
end

function Family:_additionalJSONfields(data)
	data.family = self._rawData
	data.protoLanguage = self._rawData.protoLanguage
	return data
end

require("Module:User:Theknightwho/objects").makePrototype(Family, "family")

-- TODO: sort out useRequire in other functions.
function export.makeObject(code, data, useRequire)
	return data and setmetatable({
		_rawData = data,
		_code = code,
		_useRequire = useRequire or nil
	}, Family) or nil
end

--[==[
Finds the family whose code matches the one provided. If it exists, it returns a {Family} object representing the
family. Otherwise, it returns {nil}.
]==]
function export.getByCode(code, useRequire)
	local data = conditionalRequire("Module:families/data", useRequire)
	if data then
		return export.makeObject(code, data, useRequire)
	end

	data = conditionalRequire("Module:families/data/etymology", useRequire)
	if data then
		return require("Module:languages").makeObject(code, data, useRequire)
	end

	return nil
end

--[==[
Look for the family whose canonical name (the name used to represent that language on Wiktionary) matches the one
provided. If it exists, it returns a {Family} object representing the family. Otherwise, it returns {nil}. The
canonical name of families should always be unique (it is an error for two families on Wiktionary to share the same
canonical name), so this is guaranteed to give at most one result.
]==]
function export.getByCanonicalName(name, useRequire)
	local byName = conditionalRequire("Module:families/canonical names", useRequire)
	local code = byName and byName or
		byName
	return export.getByCode(code, useRequire)
end

return export