Module:MLB standings/sandbox

-- This module copies content from Template:MLB_standings; see the history of that page

-- for attribution.

local me = { }

local mlbData = mw.loadData('Module:MLB standings/data')

local Navbar = require('Module:Navbar')

--

-- defaultOutputForInput: table mapping from input format to default output format

-- (if the output format is not specified in the template arguments)

--

local defaultOutputForInput = {

default = 'default',

overallWinLoss = 'winLossOnly',

}

--

-- readTeamInfo: table of input parsers

-- Keys are the input formats, values are functions that parse the unnamed parameters

-- that were passed to the template and return a table holding the team name

-- and the win-loss records (either overall, or home and away, depending on the

-- input format).

-- The parsers take the following parameters:

-- args: table holding the parameters (indexed by numeric position)

-- currentIdx: the current index from where the next set of data should be parsed

-- returnData: table that the parser will update to pass additional data back to the caller.

-- returnData.cIndicesRead is updated with the number of parameters that were parsed

--

local readTeamInfo = {

default = function(args, currentIdx, returnData)

if (args[currentIdx] == nil or

args[currentIdx+1] == nil or

args[currentIdx+2] == nil or

args[currentIdx+3] == nil or

args[currentIdx+4] == nil ) then

return nil

end

teamInfo = {

name = mw.text.trim(args[currentIdx]),

homeWins = tonumber(mw.text.trim(args[currentIdx+1])),

homeLosses = tonumber(mw.text.trim(args[currentIdx+2])),

roadWins = tonumber(mw.text.trim(args[currentIdx+3])),

roadLosses = tonumber(mw.text.trim(args[currentIdx+4])),

}

returnData.cIndicesRead = 5

teamInfo.wins = teamInfo.homeWins + teamInfo.roadWins

teamInfo.losses = teamInfo.homeLosses + teamInfo.roadLosses

return teamInfo

end, -- function readTeamInfo.default()

overallWinLoss = function(args, currentIdx, returnData)

if (args[currentIdx] == nil or

args[currentIdx+1] == nil or

args[currentIdx+2] == nil ) then

return nil

end

teamInfo = {

name = mw.text.trim(args[currentIdx]),

wins = tonumber(mw.text.trim(args[currentIdx+1])),

losses = tonumber(mw.text.trim(args[currentIdx+2])),

}

returnData.cIndicesRead = 3

return teamInfo

end, -- function readTeamInfo.default()

} -- readTeamInfo object

--

-- generateTableHeader: table of functions that generate table header

-- Keys are the output formats, values are functions that return a string with the table header

-- The generator functions take the following parameter:

-- tableHeaderInfo: table that contains the information needed for the header

--

local generateTableHeader = {

default = function(tableHeaderInfo)

return

'

class="wikitable MLBStandingsTable" \

|+ |' .. tableHeaderInfo.navbarText .. '[[' .. tableHeaderInfo.divisionLink

.. '|' .. tableHeaderInfo.division .. ']]\

\

! width="51%" | Team \

! width="6%" | W\

! width="6%" | L\

! width="9%" | Pct.\

! width="8%" | GB\

! width="10%" | Home\

! width="10%" | Road\

'

end, -- function generateTableHeader.default()

winLossOnly = function(tableHeaderInfo)

return

'{| class="wikitable MLBStandingsTable" \

|+ |' .. tableHeaderInfo.navbarText .. tableHeaderInfo.division .. '\

\

! width="66%" | Team\

! width="10%" | W\

! width="10%" | L\

! width="14%" | Pct.\

'

end, -- function generateTableHeader.winLossOnlyNoNavBar()

wildCard2012 = function(tableHeaderInfo)

return

'{| class="wikitable MLBStandingsTable" \

|+ |' .. tableHeaderInfo.navbarText .. 'Wild Card teams
(Top 2 teams qualify for postseason)\

\

! width="64%" | Team \

! width="8%" | W\

! width="8%" | L\

! width="10%" | Pct.\

! width="10%" | GB\

'

end, -- function generateTableHeader.wildCard2012

wildCard = function(tableHeaderInfo)

local teamText = 'team'

local numberOfTeamsText = 'team qualifies'

if tableHeaderInfo.wildCardsPerLeague > 1 then

teamText = 'teams'

numberOfTeamsText = tableHeaderInfo.wildCardsPerLeague .. ' teams qualify'

end

return

'{| class="wikitable MLBStandingsTable" \

|+ |' .. tableHeaderInfo.navbarText .. 'Wild Card ' .. teamText .. '
(Top ' .. numberOfTeamsText ..

' for postseason)\

\

! width="64%" | Team \

! width="8%" | W\

! width="8%" | L\

! width="10%" | Pct.\

! width="10%" | GB\

'

end, -- function generateTableHeader.wildCard

} -- generateTableHeader object

--

-- generateTeamRow: table of functions that generate a table row

-- Keys are the output formats, values are functions that return a string with the table row

-- The generator functions take the following parameter:

-- tableRowInfo: table that contains additional the information needed for the row

-- teamInfo: table that contains the team name and win-loss info

--

local generateTeamRow = {

default = function(teamRowInfo, teamInfo)

return

'

' .. teamRowInfo.rowStyle .. '\' .. teamRowInfo.seedText .. '' .. teamInfo.name .. '\' .. teamInfo.wins .. '' .. teamInfo.losses .. '\' .. teamRowInfo.winningPercentage .. '\' .. teamRowInfo.gamesBehind .. '\' .. teamInfo.homeWins .. '‍–‍' .. teamInfo.homeLosses ..'\' .. teamInfo.roadWins .. '‍–‍' .. teamInfo.roadLosses .. '\n'

end, -- function generateTeamRow.default()

winLossOnly = function(teamRowInfo, teamInfo)

return

'

' .. teamRowInfo.rowStyle .. '\' .. teamRowInfo.seedText .. '' .. teamInfo.name .. '\' .. teamInfo.wins .. '' .. teamInfo.losses .. '\' .. teamRowInfo.winningPercentage .. '\n'

end, -- function generateTeamRow.winLossOnly

wildCard2012 = function(teamRowInfo, teamInfo)

return

'

' .. teamRowInfo.rowStyle .. '\' .. teamRowInfo.seedText .. '' .. teamInfo.name .. '\' .. teamInfo.wins .. '' .. teamInfo.losses .. '\' .. teamRowInfo.winningPercentage .. '\' .. teamRowInfo.gamesBehind .. '\n'

end, -- function generateTeamRow.wildCard2012

wildCard = function(teamRowInfo, teamInfo)

return

'

' .. teamRowInfo.rowStyle .. '\' .. teamRowInfo.seedText .. '' .. teamInfo.name .. '\' .. teamInfo.wins .. '' .. teamInfo.losses .. '\' .. teamRowInfo.winningPercentage .. '\' .. teamRowInfo.gamesBehind .. '\n'

end, -- function generateTeamRow.wildCard

} -- generateTeamRow object

--

-- parseSeeds: function to parse the seeds template argument

--

local function parseSeeds(seedsArg, seeds)

local seedList = mw.text.split(seedsArg, '%s*,%s*')

if (#seedList == 0) then

return

end

for idx, seed in ipairs(seedList) do

local seedData = mw.text.split(seed, '%s*:%s*')

if (#seedData >= 2) then

local seedNumber = tonumber(mw.text.trim(seedData[1]))

local team = mw.text.trim(seedData[2])

seeds[seedNumber] = team

seeds[team] = seedNumber

end

end

end -- function parseSeeds()

--

-- parseHighlightArg: function to parse the highlight template argument

--

local function parseHighlightArg(highlightArg, teamsToHighlight)

local teamList = mw.text.split(highlightArg, '%s*,%s*')

if (#teamList == 0) then

return

end

for idx, team in ipairs(teamList) do

teamsToHighlight[mw.text.trim(team)] = true

end

end -- function parseHighlightArg

--

-- parseTeamLInks: function to parse the team_links template argument

--

local function parseTeamLinks(teamLinksArg, linkForTeam)

local teamList = mw.text.split(teamLinksArg, '%s*,%s*')

if (#teamList == 0) then

return

end

for idx, teamLinkInfo in ipairs(teamList) do

local teamData = mw.text.split(teamLinkInfo, '%s*:%s*')

if (#teamData >= 2) then

local team = mw.text.trim(teamData[1])

local teamLink = mw.text.trim(teamData[2])

linkForTeam[team] = teamLink

end

end

end -- function parseTeamLinks

local function getWildCardsPerLeagueForYear(year)

if year == '' then

return 0

end

for idx, wildCardInfo in ipairs(mlbData.wildCardInfo) do

if wildCardInfo.startYear <= year and year <= wildCardInfo.endYear then

return wildCardInfo.wildCardsPerLeague;

end

end

-- year not found, thus no wild cards for specified year

return 0;

end -- function getWildCardsPerLeagueForYear

--

-- function generateStandingsTable

--

-- Parameters: frame object from template

-- frame.args.input: input format for standings info

-- if not specified, the default is team name followed by home win-loss and road win-loss records

-- - overallWinLoss: team name followed by overall win-loss record

--

-- frame.args.output: output format for standings table

-- if not specified, the output format is based on the input format (see defaultOutputForInput table):

-- - default => games behind and home and road win-loss records displayed

-- - overallWinLoss => overall win-loss records displayed, no games behind column

-- - winLossOnly: overall win-loss records displayed, no games behind column

-- - wildCard: wildcard standings table displayed

-- - wildCard2012: wildcard standings table displayed (effectively the same as wildcard for years from 2012-2021; kept for backwards compatibility)

--

-- frame.args.template_name: name of standings template

-- if not specified, the default is standings

--

-- frame.args.seeds: list of team seedings

-- frame.args.highlight: list of teams to highlight

-- frame.args.team_links: list of link targets for each team

-- If not specified, the default is just the team name.

-- This is used to generate the season page for each team, in the form

-- season

--

function me.generateStandingsTable(frame)

local inputFormat = 'default'

-- If the input parameter is specified in the template, use it as the input format.

if (frame.args.input ~= nil) then

local inputArg = mw.text.trim(frame.args.input)

if (inputArg == 'overallWinLoss') then

inputFormat = 'overallWinLoss'

end

end

local templateName = nil

if (frame.args.template_name ~= nil) then

templateName = frame.args.template_name

end

local outputFormat = defaultOutputForInput[inputFormat]

local fDisplayNavbar = true

local fDisplayGamesBehind = true

-- If the output parameter is specified in the template, use it as the output format.

-- Note no cross validation is performed to check if it is valid given the input format.

if (frame.args.output ~= nil) then

local outputArg = mw.text.trim(frame.args.output)

if (outputArg == 'winLossOnly') then

outputFormat = 'winLossOnly'

fDisplayGamesBehind = false

end

if (outputArg == 'wildCard2012') then

outputFormat = 'wildCard2012'

end

if (outputArg == 'wildCard') then

outputFormat = 'wildCard'

end

end

local year = tonumber(mw.text.trim(frame.args.year or '0'))

local division = mw.text.trim(frame.args.division or '')

local divisionLink = mw.text.trim(frame.args.division_link or division)

local wildCardsPerLeague = getWildCardsPerLeagueForYear(year)

local seedInfo = {}

if (frame.args.seeds ~= nil) then

parseSeeds(frame.args.seeds, seedInfo)

end

local teamsToHighlight = {}

if (frame.args.highlight ~= nil) then

parseHighlightArg(frame.args.highlight, teamsToHighlight)

end

local linkForTeam = {}

if (frame.args.team_links ~= nil) then

parseTeamLinks(frame.args.team_links, linkForTeam)

end

local listOfTeams = {};

local currentArgIdx = 1;

-- Parse the unnamed parameters from the template. This consists of the

-- team names and their win-loss records.

while (frame.args[currentArgIdx] ~= nil) do

local returnData = { }

local teamInfo = readTeamInfo[inputFormat](frame.args, currentArgIdx, returnData);

if (teamInfo == nil) then

break

end

if (linkForTeam[teamInfo.name] ~= nil) then

teamInfo.teamLink = linkForTeam[teamInfo.name]

else

teamInfo.teamLink = teamInfo.name

end

table.insert(listOfTeams, teamInfo)

currentArgIdx = currentArgIdx + returnData.cIndicesRead

end

if (#listOfTeams == 0) then

return ''

end

-- table to hold list of strings that will be concatenated at the end

-- to create a string with the standings table

local outputBuffer = { }

local tableHeaderInfo = {

division = division,

divisionLink = divisionLink,

wildCardsPerLeague = wildCardsPerLeague,

}

if (fDisplayNavbar) then

local divisionForNavbox = division

if (mlbData.abbreviationForDivision[division] ~= nil) then

divisionForNavbox = mlbData.abbreviationForDivision[division]

end

local standingsPage

if (templateName ~= nil) then

standingsPage = templateName

else

standingsPage = year .. ' ' .. divisionForNavbox .. ' standings'

end

tableHeaderInfo.navbarText =

Navbar.navbar({

standingsPage,

mini = 1,

style = 'float:left;width:0;',

})

end

table.insert(outputBuffer,

generateTableHeader[outputFormat](tableHeaderInfo)

)

local leadingHalfGames = nil;

if (fDisplayGamesBehind) then

local standingsLeaderIdx = 1

if (outputFormat == 'wildCard2012' and #listOfTeams > 1) then

standingsLeaderIdx = 2

end

if (outputFormat == 'wildCard' and #listOfTeams >= wildCardsPerLeague) then

standingsLeaderIdx = wildCardsPerLeague

end

local teamInfo = listOfTeams[standingsLeaderIdx]

leadingHalfGames = (teamInfo.wins - teamInfo.losses)

end

for idx, teamInfo in ipairs(listOfTeams) do

local winningPercentage = string.format(

'%.3f', teamInfo.wins / ( teamInfo.wins + teamInfo.losses )

)

winningPercentage = string.gsub(winningPercentage, '^0', '')

local teamRowInfo = {

teamSeasonPage = year .. ' ' .. teamInfo.teamLink .. ' season',

winningPercentage = winningPercentage,

gamesBehind = '',

seedText = '',

rowStyle = '',

}

if (fDisplayGamesBehind) then

local halfGamesBehind = leadingHalfGames - (teamInfo.wins - teamInfo.losses)

local prefix = nil

-- if games behind is negative, take the absolute value and prefix a +

-- character

if (halfGamesBehind < 0) then

halfGamesBehind = -halfGamesBehind

prefix = '+'

end

if (halfGamesBehind == 0) then

teamRowInfo.gamesBehind = '—'

else -- if halfGamesBehind is not 0

teamRowInfo.gamesBehind = math.floor(halfGamesBehind / 2)

if (halfGamesBehind % 2 == 1) then

if (halfGamesBehind == 1) then

teamRowInfo.gamesBehind = '½'

else

teamRowInfo.gamesBehind = teamRowInfo.gamesBehind .. '½'

end

end

if ( prefix ~= nil ) then

teamRowInfo.gamesBehind = prefix .. teamRowInfo.gamesBehind

end

end -- if halfGamesBehind is not 0

end -- if (fDisplayGamesBehind)

if (seedInfo[teamInfo.name] ~= nil) then

teamRowInfo.seedText = '(' .. seedInfo[teamInfo.name] .. ') '

teamRowInfo.rowStyle = ' class="MLBStandingsHighlightedRow"'

end

if (teamsToHighlight[teamInfo.name]) then

teamRowInfo.rowStyle = ' class="MLBStandingsHighlightedRow"'

end

table.insert(outputBuffer,

generateTeamRow[outputFormat](teamRowInfo, teamInfo)

)

end -- end of looping over listOfTeams

table.insert(outputBuffer, '

')

return table.concat(outputBuffer)

end -- function me.generateStandingsTable()

function me.generateStandingsTable_fromTemplate(frame)

return me.generateStandingsTable(frame:getParent())

end -- function me.generateStandingsTable_fromTemplate()

return me