Module:RailGauge

From NSWiki
Revision as of 08:21, 9 March 2014 by Jenlom (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

-- 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