Module:MaroScale: Difference between revisions

From MTG Wiki
Jump to navigation Jump to search
>Corveroth
No edit summary
>Corveroth
(The best part about coding is imagining all of the explosions when your latest commit goes catastrophically wrong)
Line 5: Line 5:
local MaroScale = {}
local MaroScale = {}


local function link(target, displayText)
local sub, match, gsub = mw.ustring.sub, mw.ustring.match, mw.ustring.gsub
 
-- A list of all sets which have been Standard-legal since the introduction of the Storm Scale (September 2012)
local LEGAL_EXPANSIONS = {
"Return to Ravnica",
"Gatecrash",
"Dragon's Maze",
"Magic 2014",
"Theros",
"Born of the Gods",
"Journey into Nyx",
"Magic 2015",
"Khans of Tarkir",
"Fate Reforged",
"Dragons of Tarkir",
"Magic Origins",
"Battle for Zendikar",
"Oath of the Gatewatch",
"Shadows over Innistrad",
"Eldritch Moon",
"Kaladesh",
"Aether Revolt",
"Amonkhet",
"Hour of Devastation",
}
 
local function generateLink(target, displayText)
if displayText then
if displayText then
return "[["..target.."|"..displayText.."]]"
return "[["..target.."|"..displayText.."]]"
Line 14: Line 40:


local function parseRatings(raw)
local function parseRatings(raw)
local out = {}
local outputList = {}
local newestDate, newestRating = 0, 0
local newestDate, newestRating = 0, 0
local rating, refDate, refString, t
local rating, refDate, refString, t
string.gsub(raw, "{(.-)}", function(a)
gsub(raw, "{(.-)}", function(a)
rating, refDate, refString = string.match(a, "(%d+),([%d%-]+),(.+)")
rating, refDate, refString = match(a, "(%d+),([%d%-]+),(.+)")
rating = tonumber(rating)
rating = tonumber(rating)
-- Dates MUST be yyyy-mm-dd
-- Dates MUST be yyyy-mm-dd
t = os.time({year=string.sub(refDate, 1,4), month=string.sub(refDate, 6,7), day=string.sub(refDate, 9,10),})
t = os.time({year=sub(refDate, 1,4), sub(refDate, 6,7), sub(refDate, 9,10),})
if t > newestDate then
if t > newestDate then
newestDate = t
newestDate = t
Line 28: Line 54:
end
end
table.insert(out, {rating = rating, refDate = refDate, refString = refString, t = t})
table.insert(outputList, {text = rating..refString, t = t})
end)
return newestRating, outputList
end
 
local function addPrintings(timeline, printings)
local releaseDate, t
-- Comma-separated list
gsub(printings, "([^,]+)", function(set)
releaseDate = LEGAL_EXPANSIONS[set]
-- The set name provided doesn't match a post-Storm Scale set
if not releaseDate then return end
-- Dates MUST be yyyy-mm-dd
t = os.time({year=sub(releaseDate, 1,4), sub(releaseDate, 6,7), sub(releaseDate, 9,10),})
table.insert(timeline, {text = generateLink(set), t = t})
end)
end)
-- Sort ratings into chronological order
table.sort(out, function(a,b) return a.t < b.t end)
return timeline
return out
end
end


local function sortHistory(events)
-- Sort all events into chronological order
table.sort(events, function(a,b) return a.t < b.t end)
return events
end


function MaroScale.TableBuilder(frame)
function MaroScale.TableBuilder(frame)
local args = frame:getParent().args -- coming from one layer up
local args = frame:getParent().args -- coming from one layer up
Line 47: Line 96:
         _ = args["name" .. tostring(i)]
         _ = args["name" .. tostring(i)]
         _ = args["entry" .. tostring(i)]
         _ = args["entry" .. tostring(i)]
        _ = args["subname" .. tostring(i)]
        _ = args["subentry" .. tostring(i)]
         _ = args["ratings" .. tostring(i)]
         _ = args["ratings" .. tostring(i)]
        _ = args["subratings" .. tostring(i)]
        _ = args["subnolink" .. tostring(i)]
     end
     end
-- Table type
local type = args.type
local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
tbl:tag("tr")
:tag("th"):wikitext(type):done()
:tag("th"):wikitext("Latest ranking"):done()
:tag("th"):addClass("unsortable"):wikitext("History of rankings"):done()
-- Seriously this loop is entirely too clever
-- Seriously this loop is entirely too clever
local listnums = {}
local listnums = {}
for k, v in pairs(args) do
for k, v in pairs(args) do
local listnum = ('' .. k):match('^ratings(%d+)$')
local listnum = match('' .. k, '^ratings(%d+)$')
if listnum then table.insert(listnums, tonumber(listnum)) end
if listnum then table.insert(listnums, tonumber(listnum)) end
end
end
table.sort(listnums)
table.sort(listnums)


local name, entry, ratings, subname, subentry, subratings
-- Build the table header row
local type = args.type
local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
tbl:tag("tr")
:tag("th"):wikitext(type):done()
:tag("th"):wikitext("Latest ranking"):done()
:tag("th"):addClass("unsortable"):wikitext("Timeline"):done() -- Last column can't be sorted
-- Reusable loop vars for performance
local name, entry, ratings, printings
local linkedEntry, lastRating, timeline
local row, cellText
for i, listnum in ipairs(listnums) do
for i, listnum in ipairs(listnums) do
name, entry, rawRatings, subname, subentry, rawSubratings, subnolink = args["name"..listnum], args["entry"..listnum], args["ratings"..listnum], args["subname"..listnum], args["subentry"..listnum], args["subratings"..listnum], args["subnolink"..listnum]
-- Retrieve the relevant args for this row
name, entry, ratings, printings = args["name"..listnum], args["entry"..listnum], args["ratings"..listnum], args["printings"..listnum]
local sortedRatings = parseRatings(rawRatings)
-- Create a wikilink for the entry, using name as the target article if provided
local sortedSubratings
linkedEntry = generateLink(name, entry)
local hasSubentry = subentry and rawSubratings -- subname not necessary
-- Decode the ratings into a table
if hasSubentry then
lastRating, timeline = parseRatings(ratings)
sortedSubRatings = parseRatings(rawSubratings)
-- Add any printings
end
timeline = addPrintings(timeline, printings)
-- Sort chronologically
timeline = sortTimeline(timeline)
-- Make the row
-- Make the row
local row = tbl:tag("tr")
row = tbl:tag("tr")
do
-- First cell
-- First cell
do
row:tag("td"):wikitext(linkedEntry)
local cellText
if name then cellText = link(name, entry) else cellText = link(entry) end
-- Second cell
local cellList = row:tag("td"):tag("ul"):cssText("margin-top:0; margin-left:0; list-style-type: none;"):tag("li"):cssText("display:block;"):wikitext(cellText):done()
row:tag("td"):wikitext(lastRating)
if hasSubentry then
if subnolink then
cellText = subentry
else
if subname then cellText = link(subname) else cellText = link(subentry) end
end
cellList:tag("li"):cssText("display:block; margin-left: 1.0em;"):wikitext(cellText)
end
end
-- Second cell
do
local cellText = sortedRatings[#sortedRatings].rating
local cellList = row:tag("td"):attr("data-sort-value", cellText):tag("ul"):cssText("margin-top:0; margin-left:0; list-style-type: none;"):tag("li"):cssText("display:block;"):wikitext(cellText):done()
if hasSubentry then
cellText = sortedSubRatings[#sortedSubRatings].rating
cellList:tag("li"):cssText("display:block; margin-left: 1.0em;"):wikitext(cellText)
end
end
-- Third cell
-- Third cell
do
row:tag("td"):tag("ul"):cssText("display:block; margin-top:0; margin-left:0;")
local cell = row:tag("td")
local cellList = cell:tag("ul"):cssText("margin-top:0; margin-left:0; list-style-type: none;")
for n, event in pairs(timeline) do
local firstItem = cellList:tag("li"):cssText("display:block;")
if n ~= #timeline then
local list = firstItem:tag("ul"):cssText("display:block; margin-top:0; margin-left:0;")
list:tag("li"):cssText("display:inline-block;"):wikitext(event.text .. ",&nbsp;")
for n, rating in pairs(sortedRatings) do
else
if n ~= #sortedRatings then
list:tag("li"):cssText("display:inline-block;"):wikitext(event.text)
list:tag("li"):cssText("display:inline-block;"):wikitext(rating.rating .. rating.refString .. ", ")
else
list:tag("li"):cssText("display:inline-block;"):wikitext(rating.rating .. rating.refString)
end
end
if hasSubentry then
local secondItem = cellList:tag("li"):cssText("display:block;")
local list = secondItem:tag("ul"):cssText("display:block; margin-top:0; margin-left:1.0em;")
for n, rating in pairs(sortedSubRatings) do
if n ~= #sortedSubRatings then
list:tag("li"):cssText("display:inline-block;"):wikitext(rating.rating .. rating.refString .. ", ")
else
list:tag("li"):cssText("display:inline-block;"):wikitext(rating.rating .. rating.refString)
end
end
end
end
end
end
end

Revision as of 02:48, 8 January 2017

Documentation for this module may be created at Module:MaroScale/doc

-- Little bit of Lua for building tables for the Storm and Rabiah scales.
-- Mechanics have been re-ranked in the past, and it's probably interesting to track their drift.
-- Rather than force editors to track the newest one, let's see if we can't do it in code.

local MaroScale = {}

local sub, match, gsub = mw.ustring.sub, mw.ustring.match, mw.ustring.gsub

-- A list of all sets which have been Standard-legal since the introduction of the Storm Scale (September 2012)
local LEGAL_EXPANSIONS = {
	"Return to Ravnica",
	"Gatecrash",
	"Dragon's Maze",
	"Magic 2014",
	"Theros",
	"Born of the Gods",
	"Journey into Nyx",
	"Magic 2015",
	"Khans of Tarkir",
	"Fate Reforged",
	"Dragons of Tarkir",
	"Magic Origins",
	"Battle for Zendikar",
	"Oath of the Gatewatch",
	"Shadows over Innistrad",
	"Eldritch Moon",
	"Kaladesh",
	"Aether Revolt",
	"Amonkhet",
	"Hour of Devastation",
}

local function generateLink(target, displayText)
	if displayText then
		return "[["..target.."|"..displayText.."]]"
	else
		return "[["..target.."]]"
	end
end

local function parseRatings(raw)
	local outputList = {}
	local newestDate, newestRating = 0, 0
	local rating, refDate, refString, t
	gsub(raw, "{(.-)}", function(a)
		rating, refDate, refString = match(a, "(%d+),([%d%-]+),(.+)")
		rating = tonumber(rating)
		
		-- Dates MUST be yyyy-mm-dd
		t = os.time({year=sub(refDate, 1,4), sub(refDate, 6,7), sub(refDate, 9,10),})
		if t > newestDate then
			newestDate = t
			newestRating = rating
		end
		
		table.insert(outputList, {text = rating..refString, t = t})
	end)
	
	return newestRating, outputList
end

local function addPrintings(timeline, printings)
	local releaseDate, t
	-- Comma-separated list
	gsub(printings, "([^,]+)", function(set)
		releaseDate = LEGAL_EXPANSIONS[set]
		
		-- The set name provided doesn't match a post-Storm Scale set
		if not releaseDate then return end
		
		-- Dates MUST be yyyy-mm-dd
		t = os.time({year=sub(releaseDate, 1,4), sub(releaseDate, 6,7), sub(releaseDate, 9,10),})
		
		table.insert(timeline, {text = generateLink(set), t = t})
	end)
	
	return timeline
end

local function sortHistory(events)
	-- Sort all events into chronological order
	table.sort(events, function(a,b) return a.t < b.t end)
	return events
end

	
function MaroScale.TableBuilder(frame)
	local args = frame:getParent().args -- coming from one layer up
	
	-- Imitating navbox, here. I trust they know what they're doing.
	-- Read the arguments in the order they'll be output in, to make references number in the right order.
    local _
    _ = args.type
    _ = args.above
    for i = 1, 200 do
        _ = args["name" .. tostring(i)]
        _ = args["entry" .. tostring(i)]
        _ = args["ratings" .. tostring(i)]
    end
	
	-- Seriously this loop is entirely too clever
	local listnums = {}
	for k, v in pairs(args) do
		local listnum = match('' .. k, '^ratings(%d+)$')
		if listnum then table.insert(listnums, tonumber(listnum)) end
	end
	table.sort(listnums)

	
	-- Build the table header row
	local type = args.type
	local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
	tbl:tag("tr")
		:tag("th"):wikitext(type):done()
		:tag("th"):wikitext("Latest ranking"):done()
		:tag("th"):addClass("unsortable"):wikitext("Timeline"):done() -- Last column can't be sorted
	
	-- Reusable loop vars for performance
	local name, entry, ratings, printings
	local linkedEntry, lastRating, timeline
	local row, cellText
	for i, listnum in ipairs(listnums) do
		-- Retrieve the relevant args for this row
		name, entry, ratings, printings = args["name"..listnum], args["entry"..listnum], args["ratings"..listnum], args["printings"..listnum]
		
		-- Create a wikilink for the entry, using name as the target article if provided
		linkedEntry = generateLink(name, entry)
		
		-- Decode the ratings into a table
		lastRating, timeline = parseRatings(ratings)
		-- Add any printings
		timeline = addPrintings(timeline, printings)
		-- Sort chronologically
		timeline = sortTimeline(timeline)
		
		-- Make the row
		row = tbl:tag("tr")
		
		-- First cell
		row:tag("td"):wikitext(linkedEntry)
		
		-- Second cell
		row:tag("td"):wikitext(lastRating)
			
		-- Third cell
		row:tag("td"):tag("ul"):cssText("display:block; margin-top:0; margin-left:0;")
		
		for n, event in pairs(timeline) do
			if n ~= #timeline then
				list:tag("li"):cssText("display:inline-block;"):wikitext(event.text .. ",&nbsp;")
			else
				list:tag("li"):cssText("display:inline-block;"):wikitext(event.text)
			end
		end
	end
	return tbl
end

return MaroScale