Editing Module:Template test case
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
-- | -- This module provides several methods to generate test cases. | ||
-- Load required modules | -- Load required modules | ||
local yesno = require('Module:Yesno') | local yesno = require('Module:Yesno') | ||
local mTableTools = require('Module:TableTools') | |||
-- Set constants | -- Set constants | ||
local DATA_MODULE = 'Module:Template test case/data' | local DATA_MODULE = 'Module:Template test case/data' | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
Line 54: | Line 19: | ||
getFullPage = true, | getFullPage = true, | ||
getName = true, | getName = true, | ||
makeHeading = true, | |||
getOutput = true | getOutput = true | ||
} | } | ||
Line 94: | Line 59: | ||
function Template:getFullPage() | function Template:getFullPage() | ||
if | if self.template then | ||
local strippedTemplate, hasColon = self.template:gsub('^:', '', 1) | local strippedTemplate, hasColon = self.template:gsub('^:', '', 1) | ||
hasColon = hasColon > 0 | hasColon = hasColon > 0 | ||
Line 110: | Line 71: | ||
return mw.site.namespaces[10].name .. ':' .. strippedTemplate | return mw.site.namespaces[10].name .. ':' .. strippedTemplate | ||
end | end | ||
else | |||
return self.title.prefixedText | |||
end | end | ||
end | end | ||
Line 135: | Line 98: | ||
end | end | ||
function Template: | function Template:makeHeading() | ||
return self.heading or self:makeBraceLink() | return self.heading or self:makeBraceLink() | ||
end | end | ||
function Template:getInvocation(format) | function Template:getInvocation(format) | ||
local invocation = self._invocation:getInvocation | local invocation = self._invocation:getInvocation(self:getName()) | ||
if format == 'code' then | if format == 'code' then | ||
invocation = '<code>' .. mw.text.nowiki(invocation) .. '</code>' | invocation = '<code>' .. mw.text.nowiki(invocation) .. '</code>' | ||
elseif format == 'plain' then | elseif format == 'plain' then | ||
invocation = mw.text.nowiki(invocation) | invocation = mw.text.nowiki(invocation) | ||
Line 160: | Line 118: | ||
function Template:getOutput() | function Template:getOutput() | ||
return self._invocation:getOutput(self:getName()) | |||
end | end | ||
Line 174: | Line 127: | ||
local TestCase = {} | local TestCase = {} | ||
TestCase.__index = TestCase | TestCase.__index = TestCase | ||
TestCase.renderMethods = { | TestCase.renderMethods = { | ||
Line 181: | Line 133: | ||
columns = 'renderColumns', | columns = 'renderColumns', | ||
rows = 'renderRows', | rows = 'renderRows', | ||
default = 'renderDefault' | default = 'renderDefault' | ||
} | } | ||
Line 191: | Line 140: | ||
obj.cfg = cfg | obj.cfg = cfg | ||
-- | -- Validate options | ||
do | |||
local highestNum = 0 | |||
for k in pairs(options) do | |||
if type(k) == 'string' then | |||
local num = k:match('([1-9][0-9]*)$') | |||
num = tonumber(num) | |||
if num and num > highestNum then | |||
highestNum = num | |||
end | |||
end | |||
end | end | ||
if | for i = 3, highestNum do | ||
if not options['template' .. i] then | |||
error(string.format( | |||
"one or more options ending in '%d' were " .. | |||
"detected, but no 'template%d' option was found", | |||
i, i | |||
), 2) | |||
end | |||
end | end | ||
end | end | ||
-- | -- Separate general options from options for specific templates | ||
local templateOptions = mTableTools.numData(options, true) | |||
obj.options = templateOptions.other or {} | |||
obj.options = | |||
-- | -- Normalize boolean options | ||
obj.options.showcode = yesno(obj.options.showcode) | |||
obj.options.collapsible = yesno(obj.options.collapsible) | |||
-- | -- Add default template options | ||
templateOptions[1] = templateOptions[1] or {} | templateOptions[1] = templateOptions[1] or {} | ||
templateOptions[2] = templateOptions[2] or {} | templateOptions[2] = templateOptions[2] or {} | ||
if templateOptions[1].template and not templateOptions[2].template then | if templateOptions[1].template and not templateOptions[2].template then | ||
templateOptions[2].template = templateOptions[1].template .. | templateOptions[2].template = templateOptions[1].template .. '/sandbox' | ||
end | end | ||
if not templateOptions[1].template then | if not templateOptions[1].template then | ||
Line 245: | Line 181: | ||
end | end | ||
if not templateOptions[2].template then | if not templateOptions[2].template then | ||
templateOptions[2].title = templateOptions[1].title:subPageTitle( | templateOptions[2].title = templateOptions[1].title:subPageTitle('sandbox') | ||
end | end | ||
-- Make the template objects | -- Make the template objects | ||
obj.templates = {} | obj.templates = {} | ||
for i, | for i, t in ipairs(templateOptions) do | ||
table.insert(obj.templates, Template.new(invocationObj, | table.insert(obj.templates, Template.new(invocationObj, t)) | ||
end | end | ||
Line 327: | Line 210: | ||
local out = obj:getOutput() | local out = obj:getOutput() | ||
-- Remove the random parts from strip markers. | -- Remove the random parts from strip markers. | ||
out = out:gsub('( | out = out:gsub('(%cUNIQ).-(QINU%c)', '%1%2') | ||
return out | return out | ||
end | end | ||
Line 341: | Line 224: | ||
function TestCase:makeCollapsible(s) | function TestCase:makeCollapsible(s) | ||
local isEqual = self:templateOutputIsEqual() | local isEqual = self:templateOutputIsEqual() | ||
local root = mw.html.create('table') | local root = mw.html.create('table') | ||
root | root | ||
:addClass('collapsible') | |||
:addClass(isEqual and 'collapsed' or nil) | |||
:addClass(' | |||
:css('background-color', 'transparent') | :css('background-color', 'transparent') | ||
:css('width', '100%') | :css('width', '100%') | ||
Line 387: | Line 235: | ||
:tag('th') | :tag('th') | ||
:css('background-color', isEqual and 'lightgreen' or 'yellow') | :css('background-color', isEqual and 'lightgreen' or 'yellow') | ||
:wikitext(title) | :wikitext(self.options.title or self.templates[1]:makeHeading()) | ||
:done() | :done() | ||
:done() | :done() | ||
:tag('tr') | :tag('tr') | ||
:tag('td') | :tag('td') | ||
:wikitext(s) | :wikitext(s) | ||
return tostring(root) | return tostring(root) | ||
end | end | ||
Line 408: | Line 253: | ||
local tableroot = root:tag('table') | local tableroot = root:tag('table') | ||
tableroot | |||
:addClass(self.options.class) | |||
:cssText(self.options.style) | |||
:tag('caption') | |||
:wikitext(self.options.caption or 'Side by side comparison') | |||
-- Headings | |||
local headingRow = tableroot:tag('tr') | |||
if self.options.rowheader then | |||
-- rowheader is correct here. We need to add another th cell if | |||
-- rowheader is set further down, even if heading0 is missing. | |||
headingRow:tag('th'):wikitext(self.options.heading0) | |||
end | |||
local width | |||
if #self.templates > 0 then | |||
width = tostring(math.floor(100 / #self.templates)) .. '%' | |||
else | |||
width = '100%' | |||
end | |||
for i, obj in ipairs(self.templates) do | |||
headingRow | |||
:tag('th') | |||
:css('width', width) | |||
:wikitext(obj:makeHeading()) | |||
end | end | ||
Line 450: | Line 289: | ||
-- Template output | -- Template output | ||
for i, obj in ipairs(self.templates) do | for i, obj in ipairs(self.templates) do | ||
dataRow:tag('td') | |||
:newline() | |||
:wikitext(self:getTemplateOutput(obj)) | |||
:wikitext(self.options.after) | |||
end | end | ||
Line 499: | Line 318: | ||
for _, obj in ipairs(self.templates) do | for _, obj in ipairs(self.templates) do | ||
-- Build the row HTML | |||
tableroot | |||
-- | :tag('tr') | ||
:tag('td') | |||
:css('text-align', 'center') | :css('text-align', 'center') | ||
:css('font-weight', 'bold') | :css('font-weight', 'bold') | ||
:wikitext(obj: | :wikitext(obj:makeHeading()) | ||
:done() | |||
:done() | |||
:tag('tr') | |||
:tag('td') | |||
:newline() | |||
:wikitext(self:getTemplateOutput(obj)) | |||
: | |||
end | end | ||
return tostring(root) | return tostring(root) | ||
Line 646: | Line 343: | ||
for i, obj in ipairs(self.templates) do | for i, obj in ipairs(self.templates) do | ||
ret[#ret + 1] = '<div style="clear: both;"></div>' | ret[#ret + 1] = '<div style="clear: both;"></div>' | ||
ret[#ret + 1] = obj:makeBraceLink() | |||
ret[#ret + 1] = self:getTemplateOutput(obj) | |||
end | end | ||
return table.concat(ret, '\n\n') | return table.concat(ret, '\n\n') | ||
Line 666: | Line 355: | ||
if self.options.collapsible then | if self.options.collapsible then | ||
ret = self:makeCollapsible(ret) | ret = self:makeCollapsible(ret) | ||
end | end | ||
return ret | return ret | ||
Line 679: | Line 365: | ||
local NowikiInvocation = {} | local NowikiInvocation = {} | ||
NowikiInvocation.__index = NowikiInvocation | NowikiInvocation.__index = NowikiInvocation | ||
function NowikiInvocation.new(invocation, cfg) | function NowikiInvocation.new(invocation, cfg) | ||
Line 696: | Line 381: | ||
end | end | ||
function NowikiInvocation:getInvocation( | function NowikiInvocation:getInvocation(template) | ||
template = template:gsub('%%', '%%%%') -- Escape "%" with "%%" | |||
local invocation, count = self.invocation:gsub( | local invocation, count = self.invocation:gsub( | ||
self.cfg.templateNameMagicWordPattern, | self.cfg.templateNameMagicWordPattern, | ||
template | template | ||
) | ) | ||
if | if count < 1 then | ||
error( | error(string.format( | ||
' | "the template invocation must include '%s' in place " .. | ||
"of the template name", | |||
self.cfg.templateNameMagicWord | self.cfg.templateNameMagicWord | ||
)) | )) | ||
Line 711: | Line 397: | ||
end | end | ||
function NowikiInvocation:getOutput( | function NowikiInvocation:getOutput(template) | ||
local invocation = self:getInvocation( | local invocation = self:getInvocation(template) | ||
return mw.getCurrentFrame():preprocess(invocation) | return mw.getCurrentFrame():preprocess(invocation) | ||
end | end | ||
Line 722: | Line 408: | ||
local TableInvocation = {} | local TableInvocation = {} | ||
TableInvocation.__index = TableInvocation | TableInvocation.__index = TableInvocation | ||
function TableInvocation.new(invokeArgs, nowikiCode, cfg) | function TableInvocation.new(invokeArgs, nowikiCode, cfg) | ||
Line 732: | Line 417: | ||
end | end | ||
function TableInvocation:getInvocation( | function TableInvocation:getInvocation(template) | ||
if self.code then | if self.code then | ||
local nowikiObj = NowikiInvocation | local nowikiObj = NowikiInvocation(self.code, self.cfg) | ||
return nowikiObj:getInvocation( | return nowikiObj:getInvocation(template) | ||
else | else | ||
return require('Module:Template invocation').invocation( | return require('Module:Template invocation').invocation( | ||
template, | |||
self.invokeArgs | self.invokeArgs | ||
) | ) | ||
Line 744: | Line 429: | ||
end | end | ||
function TableInvocation:getOutput( | function TableInvocation:getOutput(template) | ||
return mw.getCurrentFrame():expandTemplate{ | return mw.getCurrentFrame():expandTemplate{ | ||
title = | title = template, | ||
args = self.invokeArgs | args = self.invokeArgs | ||
} | } | ||
Line 758: | Line 437: | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
-- | -- Exports | ||
------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ||
local | local p = {} | ||
function | function p.table(args, cfg) | ||
cfg = cfg or mw.loadData(DATA_MODULE) | cfg = cfg or mw.loadData(DATA_MODULE) | ||
Line 795: | Line 471: | ||
end | end | ||
function | function p.nowiki(args, cfg) | ||
cfg = cfg or mw.loadData(DATA_MODULE) | cfg = cfg or mw.loadData(DATA_MODULE) | ||
local invocationObj = NowikiInvocation.new(args.code, cfg) | |||
local invocationObj = NowikiInvocation.new(code, cfg) | |||
args.code = nil | args.code = nil | ||
-- Assume we want to see the code as we already passed it in. | -- Assume we want to see the code as we already passed it in. | ||
args.showcode = args.showcode or true | args.showcode = args.showcode or true | ||
Line 807: | Line 481: | ||
return tostring(testCaseObj) | return tostring(testCaseObj) | ||
end | end | ||
function p.main(frame, cfg) | function p.main(frame, cfg) | ||
Line 847: | Line 515: | ||
end | end | ||
return | return p[func](args, cfg) | ||
end | end | ||