Difference between revisions of "Module:Convert/show"

From blackwiki
Jump to navigation Jump to search
blackwiki>Johnuniq
(restore: problem is obviously that need)
m (15 revisions imported)
 
(9 intermediate revisions by 2 users not shown)
Line 3: Line 3:
 
-- Also provides a function to show convert usage examples.
 
-- Also provides a function to show convert usage examples.
  
local function collection()
+
local Collection  -- a table to hold items
    -- Return a table to hold items.
+
Collection = {
    return {
+
add = function (self, item)
        n = 0,
+
if item ~= nil then
        add = function (self, item)
+
self.n = self.n + 1
            self.n = self.n + 1
+
self[self.n] = item
            self[self.n] = item
+
end
        end,
+
end,
        join = function (self, sep)
+
join = function (self, sep)
            return table.concat(self, sep)
+
return table.concat(self, sep)
        end,
+
end,
    }
+
remove = function (self, pos)
end
+
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)
 
local function strip(text)
    -- Return text with no leading/trailing whitespace.
+
-- Return text with no leading/trailing whitespace.
    return text:match("^%s*(.-)%s*$")
+
return text:match("^%s*(.-)%s*$")
 
end
 
end
  
local function frame(self_args, parent_args)
+
local function fakeFrame(selfArgs, parentArgs)
    -- Simulate enough of a MediaWiki module frame for convert.
+
-- Simulate enough of a MediaWiki module frame for convert.
    return {
+
-- This is a cheap way to call convert with specified arguments.
        args = self_args,
+
return {
        parent = parent_args and frame(parent_args, nil),
+
args = selfArgs,
        getParent = function (self) return self.parent end,
+
parent = parentArgs and fakeFrame(parentArgs, nil),
    }
+
getParent = function (self) return self.parent end,
 +
}
 
end
 
end
  
local cvt_function
+
local cvtFunction
local function call_convert(args)
+
local function callConvert(args)
    if not cvt_function then
+
if not cvtFunction then
        -- A testing program can set the global variable 'is_test_run'.
+
cvtFunction = require('Module:Convert').convert
        cvt_function = require(is_test_run and 'convert' or 'Module:Convert').convert
+
end
    end
+
return cvtFunction(fakeFrame({}, args))
    return cvt_function(frame({}, args))
 
 
end
 
end
  
local function maketable(results, units)
+
local function makeTable(frame, results, units)
    results:add('{| class="wikitable"')
+
results:add('{| class="wikitable"')
    results:add('! Unit code !! Unit symbol !! Unit name !! US name, if different')
+
results:add('! Unit code !! Unit symbol !! Unit name !! US name, if different')
    for i, ucode in ipairs(units) do
+
for i, ucode in ipairs(units) do
        local row = collection()
+
local row = Collection.new()
        row:add(ucode)
+
row:add(ucode)
        local args = { '1', ucode, abbr = 'on', disp = 'unit' }
+
local args = { '1', ucode, abbr = 'on', disp = 'unit' }
        row:add(call_convert(args))
+
row:add(callConvert(args))
        args.abbr = 'off'
+
args.abbr = 'off'
        local name1 = call_convert(args)
+
local name1 = callConvert(args)
        row:add(name1)
+
row:add(name1)
        args.sp = 'us'
+
args.sp = 'us'
        local name1_us = call_convert(args)
+
local name1_us = callConvert(args)
        if name1_us == name1 then
+
if name1_us == name1 then
            row:add('')
+
row:add('')
        else
+
else
            row:add(name1_us)
+
row:add(name1_us)
        end
+
end
        results:add('|-')
+
results:add('|-')
        results:add(strip('| ' .. row:join(' || ')))
+
results:add(strip('| ' .. row:join(' || ')))
    end
+
end
    results:add('|}')
+
results:add('|}')
    results:add('')
+
results:add('')
 
end
 
end
  
 
-- Commonly used units for main documentation.
 
-- Commonly used units for main documentation.
 
-- Can only be input units (not combinations or multiples).
 
-- Can only be input units (not combinations or multiples).
local common_units = {
+
local commonUnits = {
    ["Area"] = {
+
["Area"] = {
        heading = "Area",
+
heading = "Area",
examples = { "1.5|sqmi|km2", "1.5|sqmi|km2|abbr=on" },
+
examples = { "1.5|sqmi|km2", "1.5|sqmi|km2|abbr=off", "1.5|sqmi|km2|abbr=on" },
        "acre",
+
"acre",
        "ha",
+
"ha",
        "m2",
+
"m2",
        "cm2",
+
"cm2",
        "km2",
+
"km2",
        "sqin",
+
"sqin",
        "sqft",
+
"sqft",
        "sqyd",
+
"sqyd",
        "sqmi",
+
"sqmi",
    },
+
},
    ["Fuel efficiency"] = {
+
["Fuel efficiency"] = {
        heading = "Fuel efficiency",
+
heading = "Fuel efficiency",
examples = { "12|mpgus|km/L", "12|mpgus|km/L|abbr=on" },
+
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",
+
"km/L",
        "mpgimp",
+
"mpgimp",
        "mpgus",
+
"mpgus",
        "L/km",
+
"L/km",
        "L/100 km",
+
"L/100 km",
    },
+
},
    ["Length"] = {
+
["Length"] = {
        heading = "Length",
+
heading = "Length",
examples = { "123|cm|in", "123|cm|in|sp=us|abbr=off", "123|cm|in|abbr=on" },
+
examples = { "123|cm|in", "123|cm|in|abbr=off|sp=us", "123|cm|in|abbr=on" },
        "uin",
+
"uin",
        "in",
+
"in",
        "ft",
+
"ft",
        "yd",
+
"yd",
        "mi",
+
"mi",
        "nmi",
+
"nmi",
        "m",
+
"m",
        "cm",
+
"cm",
        "mm",
+
"mm",
        "km",
+
"km",
        "angstrom",
+
"angstrom",
    },
+
},
    ["Mass"] = {
+
["Mass"] = {
        heading = "Mass",
+
heading = "Mass",
examples = { "72.3|kg|lb", "72.3|kg|lb|abbr=on" },
+
examples = { "72.3|kg|lb", "72.3|kg|lb|abbr=off", "72.3|kg|lb|abbr=on" },
        "g",
+
"g",
        "kg",
+
"kg",
        "oz",
+
"oz",
        "lb",
+
"lb",
        "st",
+
"st",
        "LT",
+
"LT",
        "MT",
+
"MT",
        "ST",
+
"ST",
    },
+
},
    ["Pressure"] = {
+
["Pressure"] = {
        heading = "Pressure",
+
heading = "Pressure",
examples = { "28|psi|Pa", "28|psi|Pa|abbr=on" },
+
examples = { "28|psi|Pa", "28|psi|Pa|abbr=off", "28|psi|Pa|abbr=on" },
        "atm",
+
"atm",
        "mbar",
+
"mbar",
        "psi",
+
"psi",
        "Pa",
+
"Pa",
    },
+
},
    ["Speed"] = {
+
["Speed"] = {
        heading = "Speed",
+
heading = "Speed",
examples = { "60|mph|km/h", "60|mph|km/h|abbr=on" },
+
examples = { "60|mph|km/h", "60|mph|km/h|abbr=off", "60|mph|km/h|abbr=on" },
        "km/h",
+
"km/h",
        "km/s",
+
"km/s",
        "kn",
+
"kn",
        "mph",
+
"mph",
    },
+
},
    ["Temperature"] = {
+
["Temperature"] = {
        heading = "Temperature",
+
heading = "Temperature",
examples = { "100|C|F", "100|C|F|abbr=off", "100|C-change|F-change", "100|C-change|F-change|abbr=out" },
+
examples = { "100|C|F", "100|C|F|abbr=off", "100|C-change|F-change", "100|C-change|F-change|abbr=out" },
        "C",
+
"C",
        "F",
+
"F",
        "K",
+
"K",
        "C-change",
+
"C-change",
        "F-change",
+
"F-change",
        "K-change",
+
"K-change",
    },
+
},
    ["Torque"] = {
+
["Torque"] = {
        heading = "Torque",
+
heading = "Torque",
examples = { "12.5|Nm|lb.in", "12.5|Nm|lb.in|abbr=on", "12.5|Nm|lb.in|abbr=on|lk=on" },
+
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.in",
        "lb.ft",
+
"lb.ft",
        "Nm",
+
"Nm",
    },
+
},
    ["Volume"] = {
+
["Volume"] = {
        heading = "Volume",
+
heading = "Volume",
examples = { "125|cuin|l", "125|cuin|l", "125|cuin|l|abbr=on" },
+
examples = { "125|cuin|l", "125|cuin|l|abbr=off", "125|cuin|l|abbr=on" },
        "cuin",
+
"cuin",
        "cuft",
+
"cuft",
        "cuyd",
+
"cuyd",
        "cumi",
+
"cumi",
        "impgal",
+
"impgal",
        "impoz",
+
"impoz",
        "usgal",
+
"usgal",
        "usoz",
+
"usoz",
        "L",
+
"L",
        "l",
+
"l",
        "m3",
+
"m3",
        "cc",
+
"cc",
        "mm3",
+
"mm3",
    },
+
},
 
}
 
}
  
 
-- Order in which sections are wanted when doing all common units.
 
-- Order in which sections are wanted when doing all common units.
local common_sections = {
+
local commonSections = {
    "Area",
+
"Area",
    "Fuel efficiency",
+
"Fuel efficiency",
    "Length",
+
"Length",
    "Mass",
+
"Mass",
    "Pressure",
+
"Pressure",
    "Speed",
+
"Speed",
    "Temperature",
+
"Temperature",
    "Torque",
+
"Torque",
    "Volume",
+
"Volume",
 
}
 
}
  
local function _show_examples(frame, results, examples, want_table)
+
local function _showExamples(frame, results, examples, wantTable)
    local fmt
+
local fmt
    if want_table then
+
if wantTable then
        results:add('{|')
+
results:add('{|')
        fmt = '|<code>%s</code>|| → ||%s'
+
fmt = '|<code>%s</code>|| → ||%s'
    else
+
else
        fmt = '*<code>%s</code> → %s'
+
fmt = '*<code>%s</code> → %s'
    end
+
end
    for i, item in ipairs(examples) do
+
for i, item in ipairs(examples) do
        if want_table and i > 1 then
+
if wantTable and i > 1 then
            results:add('|-')
+
results:add('|-')
        end
+
end
        item = item:gsub('!', '|')
+
item = item:gsub('!', '|')
        item = '{{convert/sandboxlua' .. (item:sub(1, 1) == '|' and '' or '|') .. item .. '}}'
+
item = '{{convert' .. (item:sub(1, 1) == '|' and '' or '|') .. item .. '}}'
        results:add(fmt:format(mw.text.nowiki(item), frame:preprocess(item)))
+
results:add(fmt:format(mw.text.nowiki(item), frame:preprocess(item)))
    end
+
end
    if want_table then
+
if wantTable then
        results:add('|}')
+
results:add('|}')
    end
+
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
 
end
  
local function _show_units(frame, results, args)
+
local function showExamples(frame, wantTable)
    local do_full
+
local results = Collection.new()
    if args[1] == nil then
+
local ok, msg = pcall(_showExamples, frame, results, frame.args, wantTable)
        do_full = true
+
if ok then
        args = common_sections
+
return results:join('\n')
    end
+
end
    local group = collection()
+
return '<strong class="error">Error</strong>\n' .. msg
    for _, item in ipairs(args) do
 
        local units = common_units[item] or common_units[item:sub(1, 1):upper() .. item:sub(2)]
 
        if units then
 
            if group.n > 0 then
 
                maketable(results, group)
 
                group = collection()
 
            end
 
            if do_full then
 
                if units.heading then
 
                    results:add('===' .. units.heading .. '===')
 
                end
 
                if units.examples then
 
                    results:add('Examples:')
 
                    _show_examples(frame, results, units.examples)
 
                end
 
            end
 
            maketable(results, units)
 
        else
 
            group:add(item)
 
        end
 
    end
 
    if group.n > 0 then
 
        maketable(results, group)
 
    end
 
 
end
 
end
  
local function show_examples(frame, want_table)
+
local function showLinks(frame)
    local results = collection()
+
local results = Collection.new()
    local ok, msg = pcall(_show_examples, frame, results, frame.args, want_table)
+
local ok, msg = pcall(_showLinks, frame, results, frame.args)
    if ok then
+
if ok then
        return results:join('\n')
+
return results:join('\n')
    end
+
end
    return '<strong class="error">Error</strong>\n' .. msg
+
return '<strong class="error">Error</strong>\n' .. msg
 
end
 
end
  
local function show_units(frame)
+
local function showUnits(frame)
    local results = collection()
+
local results = Collection.new()
    local ok, msg = pcall(_show_units, frame, results, frame.args)
+
local ok, msg = pcall(_showUnits, frame, results, frame.args)
    if ok then
+
if ok then
        return results:join('\n')
+
return results:join('\n')
    end
+
end
    return '<strong class="error">Error</strong>\n' .. msg
+
return '<strong class="error">Error</strong>\n' .. msg
 
end
 
end
  
 
return {
 
return {
    unit = show_units,
+
links = showLinks,
    units = show_units,
+
unit = showUnits,
    ['list'] = function (frame) return show_examples(frame, false) end,
+
units = showUnits,
    ['table'] = function (frame) return show_examples(frame, true) end,
+
['list'] = function (frame) return showExamples(frame, false) end,
 +
['table'] = function (frame) return showExamples(frame, true) end,
 
}
 
}

Latest revision as of 15:52, 26 September 2020

This module can be used to prepare tables of wikitext to display simple documentation for specified units. Data is obtained by calling Module:Convert. In addition, the module can be used to show {{convert}} usage examples.

Listing links

See Module talk:Convert/show for a list of unique links for units. The list is shorter and easier to check than the full list of units.

Displaying unit information

The module contains a built-in list of commonly used units. The information at Help:Convert units#Units is the output from:

  • {{#invoke:convert/show|units}}

When no units are specified, the full built-in list of unit codes is used. In addition, the headings and examples defined in the module are displayed.

Units may be specified by entering section names or individual unit codes. No headings or examples are included if units are specified.

For example, one or more sections from the full list can be displayed as in the following examples:

  • {{#invoke:convert/show|units|length}}
  • {{#invoke:convert/show|units|length|mass|area}}

Any "input" unit codes can be specified individually, for example, the following line:

  • {{#invoke:convert/show|units|um|cm|ug|kg}}

gives the result:

Unit code Unit symbol Unit name US name, if different
um μm micrometre micrometer
cm cm centimetre centimeter
ug μg microgram
kg kg kilogram

Only units suitable for use as a conversion input can be used. For example, ftin cannot be used as it is an output unit which displays the result in feet and inches.

Displaying usage examples

The module can display examples of {{convert}} usage in a list or a table. The required parameters must be separated with ! (exclamation mark) rather than the normal | (pipe), and a parameter that includes an equals sign must be prefixed with 1= (for the first parameter), or 2= (for the second), etc.

For example, the following line:

  • {{#invoke:convert/show|list|1=123!cm!in!abbr=on|2=125!sqft!m2!abbr=off!sp=us}}

gives the result:

  • {{convert|123|cm|in|abbr=on}} → 123 cm (48 in)
  • {{convert|125|sqft|m2|abbr=off|sp=us}} → 125 square feet (11.6 square meters)

The same information can be displayed in a table.

  • {{#invoke:convert/show|table|1=123!cm!in!abbr=on|2=125!sqft!m2!abbr=off!sp=us}}

gives the result:

{{convert|123|cm|in|abbr=on}} 123 cm (48 in)
{{convert|125|sqft|m2|abbr=off|sp=us}} 125 square feet (11.6 square meters)

Substitution

Results from invoking the module can be substituted into the current page, for example:

  • {{subst:#invoke:convert/show|units|length}}
  • {{subst:#invoke:convert/show|table|1=123!cm!in!abbr=on|2=125!sqft!m2!abbr=off!sp=us}}

Substitution may be useful if editing of the resulting wikitext is required.


-- 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,
}