<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://the-democratika.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ARoad_data%2Fparser</id>
	<title>Module:Road data/parser - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://the-democratika.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ARoad_data%2Fparser"/>
	<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:Road_data/parser&amp;action=history"/>
	<updated>2026-04-04T18:27:45Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://the-democratika.com/wiki/index.php?title=Module:Road_data/parser&amp;diff=6719&amp;oldid=prev</id>
		<title>&gt;BrandonXLF: Add ignoreifexists to ignore ifexists</title>
		<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:Road_data/parser&amp;diff=6719&amp;oldid=prev"/>
		<updated>2024-08-24T09:40:02Z</updated>

		<summary type="html">&lt;p&gt;Add ignoreifexists to ignore ifexists&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {} -- Package to be exported&lt;br /&gt;
&lt;br /&gt;
-- Change to &amp;quot;&amp;quot; upon deployment.&lt;br /&gt;
local moduleSuffix = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local parserHooksModuleName = &amp;quot;Module:Road data/parser/hooks&amp;quot; .. moduleSuffix&lt;br /&gt;
&lt;br /&gt;
-- Local library aliases&lt;br /&gt;
local format = string.format&lt;br /&gt;
local gsub = mw.ustring.gsub&lt;br /&gt;
local upper = mw.ustring.upper&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Substitution pattern based on passed arguments&lt;br /&gt;
-- Syntax: [param|value|match|mismatch]&lt;br /&gt;
-- where&lt;br /&gt;
--  param is the parameter name to be tested&lt;br /&gt;
--  value is the value to test against argument; if empty, the argument is&lt;br /&gt;
--    tested for existence&lt;br /&gt;
--  match is the string to be substituted if the argument matches value&lt;br /&gt;
--  mismatch is the string to be substituted if the argument does not match&lt;br /&gt;
--    the value&lt;br /&gt;
-- These arguments may not contain &amp;quot;[&amp;quot;, &amp;quot;|&amp;quot;, or &amp;quot;]&amp;quot;.&lt;br /&gt;
local prepattern = &amp;quot;%[(%w+)%|([^%[|%]]*)%|([^%[|%]]*)%|([^%[|%]]*)%]&amp;quot;&lt;br /&gt;
---&lt;br /&gt;
-- Parameter substitution pattern&lt;br /&gt;
-- Syntax: %param%&lt;br /&gt;
-- where param is the name of the parameter whose value is to be substituted&lt;br /&gt;
-- in place of %param%.&lt;br /&gt;
local pattern = &amp;quot;%%(%w+)%%&amp;quot;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Perform substitutions.&lt;br /&gt;
-- @param #string formatStr The string the be substituted&lt;br /&gt;
-- @param #table args The arguments passed to this module&lt;br /&gt;
local function subst(formatStr, args)&lt;br /&gt;
	---&lt;br /&gt;
	-- Perform a substitution based on passed argument.&lt;br /&gt;
	-- @param #string param The parameter name to be tested&lt;br /&gt;
	-- @param #string value The value to test against argument; if empty,&lt;br /&gt;
	-- 		the argument is tested for existence&lt;br /&gt;
	-- @param #string ifmatch The resulting string if the argument matches&lt;br /&gt;
	-- 		`value`&lt;br /&gt;
	-- @param #string ifmismatch The resulting string if the argument does not&lt;br /&gt;
	-- 		match `value`&lt;br /&gt;
	-- @return #string either `ifmatch` or `ifmismatch`, based on the test&lt;br /&gt;
	local function testArgs(param, value, ifmatch, ifmismatch)&lt;br /&gt;
		local arg = args[param] or &amp;#039;&amp;#039;&lt;br /&gt;
		if value ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			return arg == value and ifmatch or ifmismatch&lt;br /&gt;
		else&lt;br /&gt;
			return arg ~= &amp;#039;&amp;#039; and ifmatch or ifmismatch&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- argument-test substitutions&lt;br /&gt;
	local preprocessed = gsub(formatStr, prepattern, testArgs)&lt;br /&gt;
	-- parameter substitutions&lt;br /&gt;
	return (gsub(preprocessed, pattern, args))&lt;br /&gt;
	-- gsub returns number of matches as second value.&lt;br /&gt;
	-- The enclosing parens discards it.&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Determine whether a given title exists on Wikipedia.&lt;br /&gt;
-- @param #string name The title, e.g., article name and file name,&lt;br /&gt;
-- 		without namespace prefix&lt;br /&gt;
-- @param #string key The name of the entry being translated.&lt;br /&gt;
-- @return #boolean `true` if the title exists, false otherwise&lt;br /&gt;
local function titleExists(name, key)&lt;br /&gt;
	if name == &amp;#039;&amp;#039; then return false end&lt;br /&gt;
	local namespaceModule = mw.loadData(&amp;#039;Module:Road data/parser/namespace&amp;#039;)&lt;br /&gt;
	-- Retrieve the namespace for `key`.&lt;br /&gt;
	local namespace = namespaceModule[key] or 0&lt;br /&gt;
	local title = mw.title.new(name, namespace);&lt;br /&gt;
	return title.exists&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Determine whether titles exist on Wikipedia.&lt;br /&gt;
-- @param value A string or a table containing strings of titles to be checked&lt;br /&gt;
-- 		against&lt;br /&gt;
-- @param #string key The name of the entry being translated.&lt;br /&gt;
-- @return #boolean `true` if all titles exist, false otherwise&lt;br /&gt;
local function ifexists(value, key)&lt;br /&gt;
	local valueType = type(value)&lt;br /&gt;
	if valueType == &amp;quot;table&amp;quot; then&lt;br /&gt;
		-- If `value` is a table, recursively check the existence&lt;br /&gt;
		-- for each element within the table.&lt;br /&gt;
		for _,entry in pairs(value) do&lt;br /&gt;
			if not ifexists(entry, key) then return false end&lt;br /&gt;
		end&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	-- Otherwise, `value` is a string, so check the existence for that string.&lt;br /&gt;
	return titleExists(value, key)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Perform a translation on a given entry.&lt;br /&gt;
-- @param entry An entry to be translated; may be any non-function type.&lt;br /&gt;
-- 		A table may be a parser hook specification, a switch table, or an&lt;br /&gt;
-- 		ordinary value table.  Translations are applied recursively.&lt;br /&gt;
-- @param #table args The arguments passed to this module&lt;br /&gt;
-- @param #string key The name of the entry being translated.&lt;br /&gt;
-- @return The translated entry&lt;br /&gt;
local function translate(entry, args, key)&lt;br /&gt;
	if type(entry) == &amp;quot;string&amp;quot; then&lt;br /&gt;
		return subst(entry, args) -- Substitute arguments as necessary.&lt;br /&gt;
	elseif type(entry) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		return entry&lt;br /&gt;
	elseif entry.hook then&lt;br /&gt;
		-- This entry is a parser hook.&lt;br /&gt;
		-- Requires: Parser hook must have hook field.&lt;br /&gt;
		local hook = entry.hook&lt;br /&gt;
		local parserHooksModule = require(parserHooksModuleName)&lt;br /&gt;
		local hookFunction = parserHooksModule[hook]&lt;br /&gt;
			or error(&amp;quot;Hook &amp;#039;&amp;quot; .. hook .. &amp;quot;&amp;#039; does not exist&amp;quot;, 0)&lt;br /&gt;
		return translate(hookFunction(entry, args), args, key)&lt;br /&gt;
	elseif entry.arg or entry.undefined or entry.default then&lt;br /&gt;
		-- This entry is a switch table.&lt;br /&gt;
		-- Requires: Switch table must have&lt;br /&gt;
		--           arg, undefined, or default fields&lt;br /&gt;
		--           but not hook field.&lt;br /&gt;
		local arg = args[entry.arg or &amp;quot;route&amp;quot;]&lt;br /&gt;
		if entry[arg] then return translate(entry[arg], args, key) end&lt;br /&gt;
		if arg == nil and entry.undefined ~= nil then&lt;br /&gt;
			-- result for unspecified argument&lt;br /&gt;
			return translate(entry.undefined, args, key)&lt;br /&gt;
		end&lt;br /&gt;
		-- default result for mismatch&lt;br /&gt;
		local defaultValue = translate(entry.default, args, key)&lt;br /&gt;
		if defaultValue and entry.ifexists and not args.ignoreifexists then&lt;br /&gt;
			-- Check existence.&lt;br /&gt;
			if ifexists(defaultValue, key) then return defaultValue end&lt;br /&gt;
			-- Failed existence check results in fallback value (default to nil).&lt;br /&gt;
			return entry.otherwise and translate(entry.otherwise, args, key) or nil&lt;br /&gt;
		else&lt;br /&gt;
			return defaultValue&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- This entry is a value table.&lt;br /&gt;
		-- Process each table element.&lt;br /&gt;
		local result = {}&lt;br /&gt;
		for key,elem in pairs(entry) do&lt;br /&gt;
			result[key] = translate(elem, args, key)&lt;br /&gt;
		end&lt;br /&gt;
		return result&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Retrieve an entry from a data module based on a given type and key.&lt;br /&gt;
-- @param #string module The name of the data module to be fetched&lt;br /&gt;
-- @param type The key for the type table within the loaded table&lt;br /&gt;
-- @param key The key for the entry within the type table&lt;br /&gt;
-- @return fetchedTable[type][key] if specified, where `fetchedTable` is the&lt;br /&gt;
-- 		table fetched from `module`, nil otherwise&lt;br /&gt;
local function getTypeData(module, type, key)&lt;br /&gt;
	-- Attempt to fetch the given data module.&lt;br /&gt;
	local success, moduleData = pcall(mw.loadData, module)&lt;br /&gt;
	if not success then return false, moduleData end -- Module could not be loaded&lt;br /&gt;
	-- The type table defaults to empty-key table if undefined.&lt;br /&gt;
	local typeTable = moduleData[type] or moduleData[&amp;#039;&amp;#039;]&lt;br /&gt;
	-- Fallback table is the empty-key table, with the empty table as default.&lt;br /&gt;
	local defaultTable = moduleData[&amp;#039;&amp;#039;] or {}&lt;br /&gt;
	if typeTable then&lt;br /&gt;
		local alias = typeTable.alias&lt;br /&gt;
		if alias and alias.module and alias.type then&lt;br /&gt;
			-- The type table is an alias table.&lt;br /&gt;
			-- Recursively fetch the aliased type data.&lt;br /&gt;
			local aliasedModule = &amp;quot;Module:Road data/strings/&amp;quot; .. alias.module&lt;br /&gt;
			local aliasedType = alias.type&lt;br /&gt;
			return getTypeData(aliasedModule, aliasedType, key)&lt;br /&gt;
		end&lt;br /&gt;
		return true, typeTable[key] or defaultTable[key] or nil&lt;br /&gt;
	else&lt;br /&gt;
		return true, nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Determine the module name for the lookup by country and state.&lt;br /&gt;
-- @param #table args The arguments passed to this module&lt;br /&gt;
-- @return #string The module name to be fetched&lt;br /&gt;
local function getModuleName(args)&lt;br /&gt;
	-- countries with submodules for states or provinces&lt;br /&gt;
	local stateCountries = {USA = true, CAN = true}&lt;br /&gt;
	local state = upper(args.state or args.province or &amp;#039;&amp;#039;)&lt;br /&gt;
	local country&lt;br /&gt;
	if args.country then&lt;br /&gt;
		country = upper(args.country)&lt;br /&gt;
	else&lt;br /&gt;
		-- Recover the country from the given state or province.&lt;br /&gt;
		local countryModule = mw.loadData(&amp;quot;Module:Road data/countrymask&amp;quot;)&lt;br /&gt;
		country = countryModule[state] or &amp;#039;UNK&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	if stateCountries[country] and state ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		-- Submodule within the country exists.&lt;br /&gt;
		return format(&amp;quot;Module:Road data/strings/%s/%s&amp;quot;, country, state)&lt;br /&gt;
	end&lt;br /&gt;
	return format(&amp;quot;Module:Road data/strings/%s&amp;quot;, country)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Fetch the entry from the appropriate module, and return that entry&lt;br /&gt;
-- substituted with appropriate values.&lt;br /&gt;
-- @param #table args The arguments to be used for lookup and substitutions&lt;br /&gt;
-- @param #string key The key for the entry within the type table&lt;br /&gt;
-- @param #string type (optional) The key for the type table within the fetched&lt;br /&gt;
-- 		module; defaults to args.type&lt;br /&gt;
-- @param #string moduleName (optional) The name of the module to be fetched;&lt;br /&gt;
-- 		defaults to the module determined by country and state&lt;br /&gt;
-- @return The substituted entry&lt;br /&gt;
function p.parser(args, key, type, moduleName)&lt;br /&gt;
	-- Determine module name, if not given.&lt;br /&gt;
	local dataModuleName = moduleName or getModuleName(args)&lt;br /&gt;
	-- Fetch the entry from the module.&lt;br /&gt;
	local success, formatStr = getTypeData(dataModuleName, type or args.type, key)&lt;br /&gt;
	if not success then return false, formatStr end&lt;br /&gt;
	-- Translate the entry.&lt;br /&gt;
	return translate(formatStr, args, key)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>&gt;BrandonXLF</name></author>
	</entry>
</feed>