Module:Road data/parser
Appearance
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This Lua module is used on approximately 41,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
This module exports the parser
function, which can be used from within Lua to fetch an entry from the appropriate string module. See the comment for the p.parser
function for the function's parameters.
-- Export package
local p = {}
-- Local library aliases
local format = string.format
local gsub = mw.ustring.gsub
local trim = mw.text.trim
local upper = mw.ustring.upper
-- Regex substitution patterns
local prepattern = "%[(%w+)%|(.*)%|(.*)%|(.*)%]" -- [arg|equal to (blank for existence)|if true|if false]
local pattern = "%%(%w+)%%" -- %arg%
local function parser(formatStr, args, form)
local function ifexists(name)
-- Check whether a page or file named name exists
if name == '' then return false end -- Page doesn't exist if name is blank
local title -- mw.title object
if form == 'shield' then
title = mw.title.new(name, 'Media') -- Shields are in the Media namespace
else
title = mw.title.new(name, 0) -- Links are in the mainspace
end
return title.exists -- A boolean for whether the page exists
end
local function testArgs(test, equals, ifexists, ifnot)
-- Implement the if test
if equals ~= '' then -- Argument equals something
if args[test] == equals then return ifexists else return ifnot end
else -- Existence of argument
if args[test] and args[test] ~= '' then return ifexists else return ifnot end
end
end
local formatTable = {} -- Table with definitions
-- Recursively dig into tables that could be parser hooks or argument tables.
local function formatStrInTable(formatStr)
if type(formatStr) ~= "table" then return formatStr end -- formatStr is a scalar
formatTable = formatStr
local hook = formatStr.hook -- Possible hook
local both = formatStr[2] -- Second shield
if both then
local first = formatStrInTable(formatStr[1])
local second = formatStrInTable(both)
return {first, second} -- First and second shield
elseif hook then
local hooksModule = require "Module:Road data/parser/hooks"
local hookFunction = hooksModule[hook] or error("Hook '" .. hook .. "' does not exist", 0)
return formatStrInTable(hookFunction(formatStr, args)) -- Call hook
else -- Switch on an argument
local arg = args[formatStr.arg or "route"]
return formatStrInTable(formatStr[arg] or formatStr.default)
end
end
local function parse(formatStr)
local preprocessed = gsub(formatStr, prepattern, testArgs) -- If statements
local parsedStr = gsub(preprocessed, pattern, args) -- Variable interpolation
local final = trim(parsedStr) -- Trim extra spaces
if formatTable.ifexists then -- Existence test
local exists = ifexists(final)
if exists then
return final
else
return parser(formatTable.otherwise, args, form)
end
end
return final
end
formatStr = formatStrInTable(formatStr) -- Get formatStr
if not formatStr or formatStr == '' then return '' end -- Return empty string for empty formatStr
if type(formatStr) == 'table' then -- Dual shields
local first = parse(formatStr[1])
local second = parse(formatStr[2])
return first, second
else
return parse(formatStr)
end
end
local function formatString(args, form)
-- Get format string/table from module based on jurisdiction and type
local function getTypeData(module, type)
-- Get data from module for particular type
local success, moduleData = pcall(mw.loadData, module)
if not success then return '' end -- Empty string if module cannot be loaded
local typeTable = moduleData[type] or moduleData[''] -- Type table or empty string default table
local defaultTable = moduleData[''] or {} -- Default table
if typeTable then
local alias = typeTable.alias
if alias then -- Type is an alias to another module
local aliasedModule = "Module:Road data/strings/" .. alias.module
local aliasedType = alias.type
return getTypeData(aliasedModule, aliasedType)
end
return typeTable[form] or defaultTable[form] or ''
else
return ''
end
end
local stateCountries = {USA = true, CAN = true} -- These countries have state/province modules
local state = upper(args.state or '')
local country
if args.country then
country = upper(args.country)
else -- Find country via a mask
local countryModule = mw.loadData("Module:Road data/countrymask")
country = countryModule[state] or 'UNK'
end
local typeArg = args.type
local module
if stateCountries[country] and state ~= '' then
module = format("Module:Road data/strings/%s/%s", country, state)
else
module = format("Module:Road data/strings/%s", country)
end
return getTypeData(module, typeArg)
end
function p.parser(passedArgs, form)
local args = {state = passedArgs.state, type = passedArgs.type, route = passedArgs.route,
denom = passedArgs.denom, county = passedArgs.county, dab = passedArgs.dab,
country = passedArgs.country, township = passedArgs.township}
local formatStr = formatString(args, form)
if not formatStr or formatStr == '' then return nil end
return parser(formatStr, args, form)
end
return p