:wikitext(mw.text.nowiki(self.options.after or ""))
else
dataRow:tag('td')
:newline
:wikitext(self.options.before)
:wikitext(self:getTemplateOutput(obj))
:wikitext(self.options.after)
end
end  
return tostring(root)
end  
function TestCase:renderDefault
local ret = {}
if self.options.showcode then
ret[#ret + 1] = self.templates[1]:getInvocation
end
for i, obj in ipairs(self.templates) do
ret[#ret + 1] = '<div></div>'
if self.options.showheader then
ret[#ret + 1] = obj:makeHeader
end
if self.options.output == 'nowiki+' then
ret[#ret + 1] = self:getTemplateOutput(obj) ..
'<pre>' ..
mw.text.nowiki(self:getTemplateOutput(obj)) .. '</pre>'
elseif self.options.output == 'nowiki' then
ret[#ret + 1] = mw.text.nowiki(self:getTemplateOutput(obj))
else
ret[#ret + 1] = self:getTemplateOutput(obj)
end
end
return table.concat(ret, '\n\n')
end  
function TestCase:__tostring
local format = self.options.format
local method = format and TestCase.renderMethods[format] or 'renderDefault'
local ret = self[method](self)
if self.options.collapsible then
ret = self:makeCollapsible(ret)
end
for cat in pairs(self.categories) do
ret = ret .. string.format('', cat)
end
return ret
end  
---
-- Nowiki invocation class
---  
local NowikiInvocation = {}
NowikiInvocation.__index = NowikiInvocation
NowikiInvocation.message = message -- Add the message method  
function NowikiInvocation.new(invocation, cfg)
local obj = setmetatable({}, NowikiInvocation)
obj.cfg = cfg
invocation = mw.text.unstrip(invocation)
-- Decode HTML entities for <, >, and ". This means that HTML entities in
-- the original code must be escaped as e.g. &amp;lt;, which is unfortunate,
-- but it is the best we can do as the distinction between <, >, " and &lt;,
-- &gt;, &quot; is lost during the original nowiki operation.
invocation = invocation:gsub('&lt;', '<')
invocation = invocation:gsub('&gt;', '>')
invocation = invocation:gsub('&quot;', '"')
obj.invocation = invocation
return obj
end  
function NowikiInvocation:getInvocation(options)
local template = options.template:gsub('%%', '%%%%') -- Escape "%" with "%%"
local invocation, count = self.invocation:gsub(
self.cfg.templateNameMagicWordPattern,
template
if options.requireMagicWord ~= false and count < 1 then
error(self:message(
'nowiki-magic-word-error',
self.cfg.templateNameMagicWord
))
end
return invocation
end  
function NowikiInvocation:getOutput(options)
local invocation = self:getInvocation(options)
return mw.getCurrentFrame:preprocess(invocation)
end  
---
-- Table invocation class
---  
local TableInvocation = {}
TableInvocation.__index = TableInvocation
TableInvocation.message = message -- Add the message method  
function TableInvocation.new(invokeArgs, nowikiCode, cfg)
local obj = setmetatable({}, TableInvocation)
obj.cfg = cfg
obj.invokeArgs = invokeArgs
obj.code = nowikiCode
return obj
end  
function TableInvocation:getInvocation(options)
if self.code then
local nowikiObj = NowikiInvocation.new(self.code, self.cfg)
return nowikiObj:getInvocation(options)
else
return require('Module:Template invocation').invocation(
options.template,
self.invokeArgs
end
end  
function TableInvocation:getOutput(options)
if (options.template:sub(1, 7) == '#invoke') then
local moduleCall = mw.text.split(options.template, '|', true)
local args = mw.clone(self.invokeArgs)
table.insert(args, 1, moduleCall[2])
return mw.getCurrentFrame:callParserFunction(moduleCall[1], args)
end
return mw.getCurrentFrame:expandTemplate{
title = options.template,
args = self.invokeArgs
}
end  
---
-- Bridge functions
---
-- These functions translate template arguments into forms that can be accepted
-- by the different classes, and return the results.
---  
local bridge = {}  
function bridge.table(args, cfg)
cfg = cfg or mw.loadData(DATA_MODULE)  
local options, invokeArgs = {}, {}
for k, v in pairs(args) do
local optionKey = type(k) == 'string' and k:match('^_(.*)$')
if optionKey then
if type(v) == 'string' then
v = v:match('^%s*(.-)%s*$') -- trim whitespace
end
if v ~= '' then
options[optionKey] = v
end
else
invokeArgs[k] = v
end
end  
-- Allow passing a nowiki invocation as an option. While this means users
-- have to pass in the code twice, whitespace is preserved and &lt; etc.
-- will work as intended.
local nowikiCode = options.code
options.code = nil  
local invocationObj = TableInvocation.new(invokeArgs, nowikiCode, cfg)
local testCaseObj = TestCase.new(invocationObj, options, cfg)
return tostring(testCaseObj)
end  
function bridge.nowiki(args, cfg)
cfg = cfg or mw.loadData(DATA_MODULE)  
local code = args.code or args[1]
local invocationObj = NowikiInvocation.new(code, cfg)
args.code = nil
args[1] = nil
-- Assume we want to see the code as we already passed it in.
args.showcode = args.showcode or true
local testCaseObj = TestCase.new(invocationObj, args, cfg)
return tostring(testCaseObj)
end  
---
-- Exports
---  
local p = {}  
function p.main(, cfg)
cfg = cfg or mw.loadData(DATA_MODULE)  
-- Load the wrapper config, if any.
local wrapperConfig
if .getParent then
local title = :getParent:getTitle
local template = title:gsub(cfg.sandboxSubpagePattern, '')
wrapperConfig = cfg.wrappers[template]
end  
-- Work out the function we will call, use it to generate the config for
-- Module:Arguments, and use Module:Arguments to find the arguments passed
-- by the user.
local func = wrapperConfig and wrapperConfig.func or 'table'
local userArgs = require('Module:Arguments').getArgs(, {
parentOnly = wrapperConfig,
frameOnly = not wrapperConfig,
trim = func ~= 'table',
removeBlanks = func ~= 'table'
})  
-- Get default args and build the args table. User-specified args overwrite
-- default args.
local defaultArgs = wrapperConfig and wrapperConfig.args or {}
local args = {}
for k, v in pairs(defaultArgs) do
args[k] = v
end
for k, v in pairs(userArgs) do
args[k] = v
end  
return bridge[func](args, cfg)
end  
function p._exportClasses -- For testing
return {
Template = Template,
TestCase = TestCase,
NowikiInvocation = NowikiInvocation,
TableInvocation = TableInvocation
}
end  
return p