Module:RailGauge
-- This module implements the Script error template.
local p = {}
-- Adds span tags to prevent a string from wrapping. local function noWrap( s )
return mw.ustring.format( '%s', s )
end
-- A slimmed-down version of the Template:Frac template. local function frac( whole, num, den )
return mw.ustring.format( '%s%s%s⁄%s', whole or , whole and ' ' or , num, den )
end
-- Formats imperial measurements. Originally same functionality as Template:RailGauge/format imp. local function formatImp( data, ulink, articleLink, pageName )
local ret = {} local ft = data.ft if ft then local ftlink = ulink and not articleLink and 'ft' or 'ft' table.insert( ret, mw.ustring.format( '%s %s', ft, ftlink ) ) end local inches = data['in'] local num = data.num local den = data.den if inches and not num and not den then table.insert( ret, inches ) elseif num and den then table.insert( ret, frac( inches, num, den ) ) end if inches or num and den then local incheslink = ulink and not articleLink and 'in' or 'in' table.insert( ret, incheslink ) end local gaugeSize = noWrap( table.concat( ret, ' ' ) ) if articleLink then return '' .. gaugeSize .. '' else return gaugeSize end
end
-- Formats metric measurements. Originally same functionality as Template:RailGauge/format met local function formatMet( data, ulink, articleLink, pageName )
local m = data.m local gaugeSize if m then local munit = link and not articleLink and 'm' or 'm' gaugeSize = noWrap( mw.ustring.format( '%s %s', m, munit ) ) else local mm = data.mm mm = tonumber( mm ) if mm then mm = mw.getContentLanguage():formatNum( mm ) end local mmunit = ulink and not articleLink and 'mm' or 'mm' gaugeSize = noWrap( mw.ustring.format( '%s %s', mm, mmunit ) ) end if articleLink then return '' .. gaugeSize .. '' else return gaugeSize end
end
-- Composes the initial output from the gauge data taken from Module:RailGauge/data. -- Same functionality as Template:RailGauge/compose. local function compose( args, data )
local definition = data.dflt1 local pageName = data.pagename or nil local imp = formatImp( data, args.unitlink == 'on', args.lk=='on' and definition=='imp' and pageName, pageName) local met = formatMet( data, args.unitlink == 'on', args.lk=='on' and definition=='met' and pageName, pageName) local first = args.first or data.dflt1 if first == 'met' or first == 'metric' then first = 'met' else first = 'imp' end local ret = {} if first == 'met' then table.insert( ret, met ) else table.insert( ret, imp ) end local disp = args.disp if disp ~= '1' then local formatText if disp == 's' then formatText = '/%s' elseif disp == 'or' then formatText = ' or %s' else formatText = ' (%s)' end if first == 'met' then table.insert( ret, mw.ustring.format( formatText, imp ) ) else table.insert( ret, mw.ustring.format( formatText, met ) ) end end ret = table.concat( ret ) if args.wrap == 'y' then return ret else return noWrap( ret ) end
end
-- The basic data flow of the module. local function _main( args )
local gaugeData = mw.loadData( 'Module:RailGauge/data' ) local searchKey = mw.ustring.lower( args[ 1 ] or ) searchKey = mw.ustring.gsub( searchKey, '%s', ) -- Remove all whitespace. local title = mw.title.getCurrentTitle()
-- Get the gauge information from the /data subpage. local data for i, t in ipairs( gaugeData ) do for j, alias in ipairs( t.aliases ) do if alias == searchKey then data = t end end end
-- Categorise the page if no gauge information was found. if not data then local category = local unknownAlias = args[ 1 ] if title.namespace == 0 then category = mw.ustring.format( , unknownAlias or ' ', title.text ) end return ( unknownAlias or ) .. category end
-- Assemble the output. local ret = {} table.insert( ret, compose( args, data ) ) local gaugeName = data.name local gaugeLink = data.link if args.allk == 'on' and gaugeLink then table.insert( ret, ' ' .. noWrap( gaugeLink ) ) elseif args.al == 'on' and gaugeName then table.insert( ret, ' ' .. noWrap( gaugeName ) ) end
local maintCat = data.maintcat if maintCat and title.namespace == 0 then category = mw.ustring.format( , maintCat, title.text ) table.insert( ret, ' ' .. category ) end
return table.concat( ret )
end
function p.main( frame )
-- If called via #invoke, use the args passed into the invoking -- template, or the args passed to #invoke if any exist. Otherwise -- assume args are being passed directly in from the debug console -- or from another Lua module. local origArgs if frame == mw.getCurrentFrame() then origArgs = frame:getParent().args for k, v in pairs( frame.args ) do origArgs = frame.args break end else origArgs = frame end
-- Trim whitespace, make lower-case and remove blank arguments for all arguments but [1]. -- [1] is trimmed and blank values are removed, but capitalization is preserved when -- when no gauge data is found. local args = {} for k, v in pairs( origArgs ) do v = mw.text.trim( v ) if k == 1 and v ~= then args[ 1 ] = v elseif v ~= then args[ k ] = mw.ustring.lower( v ) end end return _main( args )
end
-- Performs various checks on the /data subpage. function p.checkData( frame )
local dataPage = frame and frame.args and frame.args[1] or 'Module:RailGauge/data' local data = mw.loadData( dataPage ) local exists, dupes, dupeSort, ret = {}, {}, {}, {} -- Check for duplicate aliases. for ti, t in ipairs( data ) do for ai, alias in ipairs( t.aliases or {} ) do if not exists[ alias ] then exists[ alias ] = { ti, ai } else if not dupes[ alias ] then dupes[ alias ] = { exists[ alias ] } end table.insert( dupes[ alias ], { ti, ai } ) end end end for alias in pairs( dupes ) do table.insert( dupeSort, alias ) end table.sort( dupeSort ) for i1, alias in ipairs( dupeSort ) do local positions = {} for i2, aliasKeys in ipairs( dupes[ alias ] ) do local position = mw.ustring.format( 'gauge %d, alias %d (gauge id:%s
)', aliasKeys[ 1 ], aliasKeys[ 2 ], data[ aliasKeys[ 1 ] ].id or ) table.insert( positions, position ) end local aliasText = mw.ustring.format( 'Duplicate aliases "%s" detected at the following positions: %s.', alias, mw.text.listToText( positions, '; ' ) ) table.insert( ret, aliasText ) end -- Check for numerators without denominators. for ti, t in ipairs( data ) do local num = t.num local den = t.den if num and not den then table.insert( ret, mw.ustring.format( 'Numerator "%s" with no denominator detected at gauge %d (id:%s
).', num, ti, t.id or ) ) elseif den and not num then table.insert( ret, mw.ustring.format( 'Denominator "%s" with no numerator detected at gauge %d (id:%s
).', den, ti, t.id or ) ) end end -- Check for gauges with no imperial or no metric measurements. for ti, t in ipairs( data ) do if not ( t.ft or t['in'] or t.num or t.den ) then table.insert( ret, mw.ustring.format( 'No imperial measurements found for gauge %d (id:%s
).', ti, t.id or ) ) end if not ( t.m or t.mm ) then table.insert( ret, mw.ustring.format( 'No metric measurements found for gauge %d (id:%s
).', ti, t.id or ) ) end end -- Check for non-numeric measurements. local measurements = { 'ft', 'in', 'num', 'den', 'm', 'mm' } for ti, t in ipairs( data ) do for mi, measurement in ipairs( measurements ) do local measurementVal = t[ measurement ] if measurementVal and not tonumber( measurementVal ) then table.insert( ret, mw.ustring.format( 'Non-numeric%s
measurement ("%s") found for gauge %d (id:%s
).', measurement, measurementVal, ti, t.id or ) ) end end end -- Check for gauges with no id. for ti, t in ipairs( data ) do if not t.id then local aliases = {} for i, alias in ipairs( t.aliases ) do table.insert( aliases, mw.ustring.format( '%s
', alias ) ) end aliases = mw.ustring.format( ' (aliases: %s)', mw.text.listToText( aliases ) ) table.insert( ret, mw.ustring.format( 'No id found for gauge %d%s.', ti, aliases or ) ) end end -- Check for gauges with no aliases. for ti, t in ipairs( data ) do if type( t.aliases ) ~= 'table' then table.insert( ret, mw.ustring.format( 'No aliases found for gauge %d (id:%s
).', ti, t.id or ) ) else local isAlias = false for ai, alias in ipairs( t.aliases ) do isAlias = true break end if not isAlias then table.insert( ret, mw.ustring.format( 'No aliases found for gauge %d (id:%s
).', ti, t.id or ) ) end end end -- Check for named gauges with no links and gauges with links but no names. for ti, t in ipairs( data ) do if t.name and not t.link then table.insert( ret, mw.ustring.format( 'No link found for the named gauge "%s" at position %d (id:%s
).', t.name, ti, t.id or ) ) elseif t.link and not t.name then table.insert( ret, mw.ustring.format( 'No name found for the gauge with link "%s" at position %d (id:%s
).', t.link, ti, t.id or ) ) end end -- Check for invalid dflt1 values. for ti, t in ipairs( data ) do local dflt1 = t.dflt1 if dflt1 ~= 'imp' and dflt1 ~= 'met' then table.insert( ret, mw.ustring.format( 'Invalid dflt1 value "%s" found for gauge %d (id:%s
).', dflt1 or , ti, t.id or ) ) end end -- Check for unwanted whitespace. for ti, t in ipairs( data ) do for tkey, tval in pairs( t ) do if tkey == 'aliases' and type( tval ) == 'table' then for ai, alias in ipairs( tval ) do if mw.ustring.find( alias, '%s' ) then table.insert( ret, mw.ustring.format( 'Unwanted whitespace detected in gauge %d alias %d ("%s", gauge id:%s
).', ti, ai, alias, t.id or ) ) end end elseif tkey == 'name' or tkey == 'link' or tkey == 'pagename' then if tval ~= mw.text.trim( tval ) then table.insert( ret, mw.ustring.format( 'Unwanted whitespace detected in%s
field of gauge %d ("%s", gauge id:%s
).', tkey, ti, tval, t.id or ) ) end elseif mw.ustring.find( tval, '%s' ) then table.insert( ret, mw.ustring.format( 'Unwanted whitespace detected in%s
field of gauge %d ("%s", gauge id:%s
).', tkey, ti, tval, t.id or ) ) end end end -- Return any errors found. for i, msg in ipairs( ret ) do ret[ i ] = mw.ustring.format( '%s', msg ) end if #ret > 0 then return mw.ustring.format( 'Found the following errors in %s:\n* %s', dataPage, table.concat( ret, '\n* ' ) ) else return mw.ustring.format( 'No errors found in %s.', dataPage ) end
end
return p