మాడ్యూల్:Convert/show
Appearance
-- Prepare tables of wikitext to display simple documentation about
-- specified units. Data is obtained by calling Module:Convert.
-- Also provides a function to show convert usage examples.
local Collection -- a table to hold items
Collection = {
add = function (self, item)
if item ~= nil then
self.n = self.n + 1
self[self.n] = item
end
end,
join = function (self, sep)
return table.concat(self, sep)
end,
remove = function (self, pos)
if self.n > 0 and (pos == nil or (0 < pos and pos <= self.n)) then
self.n = self.n - 1
return table.remove(self, pos)
end
end,
sort = function (self, comp)
table.sort(self, comp)
end,
new = function ()
return setmetatable({n = 0}, Collection)
end
}
Collection.__index = Collection
local function strip(text)
-- Return text with no leading/trailing whitespace.
return text:match("^%s*(.-)%s*$")
end
local function fakeFrame(selfArgs, parentArgs)
-- Simulate enough of a MediaWiki module frame for convert.
-- This is a cheap way to call convert with specified arguments.
return {
args = selfArgs,
parent = parentArgs and fakeFrame(parentArgs, nil),
getParent = function (self) return self.parent end,
}
end
local cvtFunction
local function callConvert(args)
if not cvtFunction then
cvtFunction = require('Module:Convert').convert
end
return cvtFunction(fakeFrame({}, args))
end
local function makeTable(frame, results, units)
results:add('{| class="wikitable"')
results:add('! Unit code !! Unit symbol !! Unit name !! US name, if different')
for i, ucode in ipairs(units) do
local row = Collection.new()
row:add(ucode)
local args = { '1', ucode, abbr = 'on', disp = 'unit' }
row:add(callConvert(args))
args.abbr = 'off'
local name1 = callConvert(args)
row:add(name1)
args.sp = 'us'
local name1_us = callConvert(args)
if name1_us == name1 then
row:add('')
else
row:add(name1_us)
end
results:add('|-')
results:add(strip('| ' .. row:join(' || ')))
end
results:add('|}')
results:add('')
end
-- Commonly used units for main documentation.
-- Can only be input units (not combinations or multiples).
local commonUnits = {
["Area"] = {
heading = "Area",
examples = { "1.5|sqmi|km2", "1.5|sqmi|km2|abbr=off", "1.5|sqmi|km2|abbr=on" },
"acre",
"ha",
"m2",
"cm2",
"km2",
"sqin",
"sqft",
"sqyd",
"sqmi",
},
["Fuel efficiency"] = {
heading = "Fuel efficiency",
examples = { "12|mpgus|km/L", "12|mpgus|km/L|abbr=off", "12|mpgus|km/L|abbr=off|sp=us", "12|mpgus|km/L|abbr=on" },
"km/L",
"mpgimp",
"mpgus",
"L/km",
"L/100 km",
},
["Length"] = {
heading = "Length",
examples = { "123|cm|in", "123|cm|in|abbr=off|sp=us", "123|cm|in|abbr=on" },
"uin",
"in",
"ft",
"yd",
"mi",
"nmi",
"m",
"cm",
"mm",
"km",
"angstrom",
},
["Mass"] = {
heading = "Mass",
examples = { "72.3|kg|lb", "72.3|kg|lb|abbr=off", "72.3|kg|lb|abbr=on" },
"g",
"kg",
"oz",
"lb",
"st",
"LT",
"MT",
"ST",
},
["Pressure"] = {
heading = "Pressure",
examples = { "28|psi|Pa", "28|psi|Pa|abbr=off", "28|psi|Pa|abbr=on" },
"atm",
"mbar",
"psi",
"Pa",
},
["Speed"] = {
heading = "Speed",
examples = { "60|mph|km/h", "60|mph|km/h|abbr=off", "60|mph|km/h|abbr=on" },
"km/h",
"km/s",
"kn",
"mph",
},
["Temperature"] = {
heading = "Temperature",
examples = { "100|C|F", "100|C|F|abbr=off", "100|C-change|F-change", "100|C-change|F-change|abbr=out" },
"C",
"F",
"K",
"C-change",
"F-change",
"K-change",
},
["Torque"] = {
heading = "Torque",
examples = { "12.5|Nm|lb.in", "12.5|Nm|lb.in|abbr=off", "12.5|Nm|lb.in|abbr=on|lk=on" },
"lb.in",
"lb.ft",
"Nm",
},
["Volume"] = {
heading = "Volume",
examples = { "125|cuin|l", "125|cuin|l|abbr=off", "125|cuin|l|abbr=on" },
"cuin",
"cuft",
"cuyd",
"cumi",
"impgal",
"impoz",
"usgal",
"usoz",
"L",
"l",
"m3",
"cc",
"mm3",
},
}
-- Order in which sections are wanted when doing all common units.
local commonSections = {
"Area",
"Fuel efficiency",
"Length",
"Mass",
"Pressure",
"Speed",
"Temperature",
"Torque",
"Volume",
}
local function _showExamples(frame, results, examples, wantTable)
local fmt
if wantTable then
results:add('{|')
fmt = '|<code>%s</code>|| → ||%s'
else
fmt = '*<code>%s</code> → %s'
end
for i, item in ipairs(examples) do
if wantTable and i > 1 then
results:add('|-')
end
item = item:gsub('!', '|')
item = '{{convert' .. (item:sub(1, 1) == '|' and '' or '|') .. item .. '}}'
results:add(fmt:format(mw.text.nowiki(item), frame:preprocess(item)))
end
if wantTable then
results:add('|}')
end
end
local function _showLinks(frame, results, args)
local sandbox = args[1] == 'sandbox' and '/sandbox' or ''
local dataModule = 'Module:Convert/data' .. sandbox
local textModule = 'Module:Convert/text' .. sandbox
local dataCode = require(dataModule)
local textCode = require(textModule)
local uniqueLinks = {}
local links = Collection.new()
local function addLink(link)
if link and link ~= '' then
-- Some items (alias symlink, chainlk symbol) are already linked.
-- Therefore, add link syntax if not present, before testing for uniqueness.
-- There will be some duplicate targets such as [[Chain (unit)|chain]] + [[Chain (unit)|ch]].
if link:sub(1, 2) ~= '[[' then
link = '[[' .. link .. ']]'
end
if not uniqueLinks[link] then
uniqueLinks[link] = true
links:add(link)
end
end
end
for _, v in ipairs(textCode.customary_units) do
addLink(v.link)
end
for _, v in pairs(dataCode.all_units) do
-- This does not add anything for automatic per units (assuming they do not define a link).
-- That is ok because per unit x/y has link LINK(x)/LINK(y).
if v.symbol and v.symbol:sub(1, 2) == '[[' then
addLink(v.symbol)
end
if v.name1 and v.name1:sub(1, 2) == '[[' then
addLink(v.name1)
end
addLink(v.symlink)
addLink(v.link or v.name1 or (not v.per and not v.target) and v.symbol)
end
for _, v in pairs(dataCode.link_exceptions) do
addLink(v)
end
for _, v in pairs(dataCode.per_unit_fixups) do
if type(v) == 'table' then
addLink(v.link)
end
end
local function comp(a, b)
local la = a:lower(a)
local lb = b:lower(b)
if la == lb then
return a < b
end
return la < lb
end
links:sort(comp)
for _, v in ipairs(links) do
results:add('*' .. v)
end
end
local function _showUnits(frame, results, args)
local doFull
if args[1] == nil then
doFull = true
args = commonSections
end
local group = Collection.new()
for _, item in ipairs(args) do
local units = commonUnits[item] or commonUnits[item:sub(1, 1):upper() .. item:sub(2)]
if units then
if group.n > 0 then
makeTable(frame, results, group)
group = Collection.new()
end
if doFull then
if units.heading then
results:add('===' .. units.heading .. '===')
end
if units.examples then
results:add('Examples:')
_showExamples(frame, results, units.examples)
end
end
makeTable(frame, results, units)
else
group:add(item)
end
end
if group.n > 0 then
makeTable(frame, results, group)
end
end
local function showExamples(frame, wantTable)
local results = Collection.new()
local ok, msg = pcall(_showExamples, frame, results, frame.args, wantTable)
if ok then
return results:join('\n')
end
return '<strong class="error">Error</strong>\n' .. msg
end
local function showLinks(frame)
local results = Collection.new()
local ok, msg = pcall(_showLinks, frame, results, frame.args)
if ok then
return results:join('\n')
end
return '<strong class="error">Error</strong>\n' .. msg
end
local function showUnits(frame)
local results = Collection.new()
local ok, msg = pcall(_showUnits, frame, results, frame.args)
if ok then
return results:join('\n')
end
return '<strong class="error">Error</strong>\n' .. msg
end
return {
links = showLinks,
unit = showUnits,
units = showUnits,
['list'] = function (frame) return showExamples(frame, false) end,
['table'] = function (frame) return showExamples(frame, true) end,
}