Module:MaroScaleSandbox

-- Sandbox page for the MaroScale lua script -- Goals: -- learn a bit more how it's used/about Modules -- update LEGAL_EXPANSIONS -- allow for not-a-single-number phrasings to be given an approximate number for sorting but still display -- explore possibility of having dates show up in the list of ratings changes, since the current -- plain list display makes changes appear uniformly spaced when they're not -- add column for additional notes - note that Beeble Scale crams notes into Timeline column already -- Will delete this page once any useful changes are merged to core MaroScale page

-- 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 MaroScaleSandbox = {}

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

local MAX_ENTRIES = 500 -- 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"]		= "2012-10-05", ["Gatecrash"] 				= "2013-02-01", ["Dragon's Maze"] 			= "2013-05-03", ["Magic 2014"] 				= "2013-06-13", ["Theros"] 					= "2013-09-27", ["Born of the Gods"] 		= "2014-02-07", ["Journey into Nyx"]		= "2014-05-02", ["Magic 2015"] 				= "2014-07-18", ["Khans of Tarkir"] 		= "2014-09-26", ["Fate Reforged"] 			= "2015-01-23", ["Dragons of Tarkir"] 		= "2015-03-17", ["Magic Origins"] 			= "2015-07-15", ["Battle for Zendikar"] 	= "2015-10-02", ["Oath of the Gatewatch"] 	= "2016-01-22", ["Shadows over Innistrad"] 	= "2016-04-08", ["Eldritch Moon"] 			= "2016-06-22", ["Kaladesh"] 				= "2016-09-30", ["Aether Revolt"] 			= "2016-01-20", ["Amonkhet"] 				= "2017-04-28", ["Hour of Devastation"] 	= "2017-07-14", }

local function generateLink(target, displayText) if displayText then return ""..target.."" 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), month=sub(refDate, 6,7), day=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), month=sub(releaseDate, 6,7), day=sub(releaseDate, 9,10),})		table.insert(timeline, {text = generateLink(set), t = t})	end) return timeline end

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

function MaroScaleSandbox.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, MAX_ENTRIES do       _ = args["name" .. tostring(i)] _ = args["entry" .. tostring(i)] _ = args["note" .. tostring(i)] _ = args["ratings" .. tostring(i)] _ = args["printings" .. 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, {num = tonumber(listnum), alpha = args["entry"..listnum]}) end end table.sort(listnums, function(a,b) return a.alpha < b.alpha end)

-- 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 local hasNotes = false -- Reusable loop vars for performance local name, entry, note, ratings, printings local linkedEntry, lastRating, timeline local row, list, cellText for i, listnum in ipairs(listnums) do		listnum = listnum.num -- Retrieve the relevant args for this row name, entry, note, ratings, printings = args["name"..listnum], args["entry"..listnum], args["note"..listnum], args["ratings"..listnum], args["printings"..listnum] -- Create a wikilink for the entry, using name as the target article if provided linkedEntry = generateLink(entry, name) if note then if not hasNotes then hasNotes = true end linkedEntry = linkedEntry .. frame:expandTemplate({title = "efn", args = { note }}) end -- Decode the ratings into a table lastRating, timeline = parseRatings(ratings) -- Add any printings if printings then timeline = addPrintings(timeline, printings) end -- 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 list = 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 .. ", ") else list:tag("li"):cssText("display:inline-block;"):wikitext(event.text) end end end if hasNotes then return tostring(tbl) .. frame:expandTemplate({title = "notelist"}) else return tbl end end

return MaroScaleSandbox