Module:Convert/wikidata/sandbox
Appearance
![]() | This is the module sandbox page for Module:Convert/wikidata (diff). |
-- Functions to access Wikidata for Module:Convert.
local function collection()
-- Return a table to hold items.
return {
n = 0,
add = function (self, item)
self.n = self.n + 1
self[self.n] = item
end,
join = function (self, sep)
return table.concat(self, sep)
end,
}
end
local function strip_to_nil(text)
-- If text is a non-empty string, return its trimmed content,
-- otherwise return nothing (empty string or not a string).
if type(text) == 'string' then
return text:match('(%S.-)%s*$')
end
end
local function make_unit(units, parms, unit_url)
-- Return a unit code for convert or nil if unit unknown.
-- If necessary, add a dummy unit to parms so convert will use it
-- for the input without attempting a conversion since nothing
-- useful is available (for example, with unit volt).
if type(unit_url) ~= 'string' then
return nil
end
local unit = units[unit_url:match('Q%d+$')]
if type(unit) ~= 'table' then
return nil
end
if unit.ucode then
return unit.ucode -- a unit known to convert
end
parms.opt_ignore_error = true
local ucode = unit._ucode -- must be a non-empty string
local ukey, utable
if unit.si then
local base = units[unit.si]
ukey = base.symbol -- must be a non-empty string
local n1 = base.name1
local n2 = base.name2
if not n1 then
n1 = ukey
if not n2 then
n2 = n1 -- do not append 's'
end
end
utable = {
_symbol = ukey,
_name1 = n1,
_name2 = n2,
link = unit.link or base.link,
utype = n1,
prefixes = 1,
}
else
ukey = ucode
utable = {
symbol = ucode, -- must be a non-empty string
name1 = unit.name1, -- if nil, uses symbol
name2 = unit.name2, -- if nil, uses name1..'s'
link = unit.link, -- if nil, uses name1
utype = unit.name1 or unit.symbol,
}
end
local common = {
scale = 1,
default = '',
defkey = '',
linkey = '',
bad_mcode = '',
}
for k, v in pairs(common) do
utable[k] = v
end
parms.unittable = { [ukey] = utable }
return ucode
end
local function adjustparameters(tdata, parms, pid, index)
-- For Module:Convert, adjust parms (a table of {{convert}} parameters).
-- Return true if successful or return false, t where t is an error message table.
-- Given that pid is a Wikidata property identifier like 'P123',
-- try to find a value and unit for the pid.
-- If successful, replace parms[index] with the value and
-- insert the unit after index.
local qid = strip_to_nil(parms.qid) -- nil (item is current page) or requested id (expensive)
local entity = mw.wikibase.getEntity(qid)
local claims = ((entity or {}).claims or {})[pid]
if claims and claims[1] then
local first = claims[1] -- TODO taking the first claim is not adequate
if first.mainsnak and first.mainsnak.datatype == 'quantity' then
local value = (first.mainsnak.datavalue or {}).value
if value then
local amount = tostring(value.amount)
local ucode = make_unit(tdata.wikidata_units, parms, value.unit)
if amount and ucode then
if amount:sub(1, 1) == '+' then
amount = amount:sub(2)
end
parms[index] = amount
table.insert(parms, index + 1, ucode)
return true
end
end
end
end
return false, { 'cvt_wd_property', tostring(pid),
qid and (' for item ' .. tostring(qid)) or '' }
end
--------------------------------------------------------------------------------
--- List units and check syntax of definitions ---------------------------------
--------------------------------------------------------------------------------
local specifications = {
-- seq = sequence in which fields are displayed
base = {
title = 'SI base units',
fields = {
symbol = { seq = 2, mandatory = true },
name1 = { seq = 3, mandatory = true },
name2 = { seq = 4 },
link = { seq = 5 },
},
noteseq = 6,
header = '{| class="wikitable"\n!si !!symbol !!name1 !!name2 !!link !!note',
item = '|-\n|%s ||%s ||%s ||%s ||%s ||%s',
footer = '|}',
},
known = {
title = 'Units known to convert',
fields = {
ucode = { seq = 2, mandatory = true },
label = { seq = 3, mandatory = true },
},
noteseq = 4,
header = '{| class="wikitable"\n!qid !!ucode !!label !!note',
item = '|-\n|%s ||%s ||%s ||%s',
footer = '|}',
},
unknown = {
title = 'Units not known to convert',
fields = {
_ucode = { seq = 2, mandatory = true },
si = { seq = 3, si = true },
name1 = { seq = 4 },
name2 = { seq = 5 },
link = { seq = 6 },
label = { seq = 7, mandatory = true },
},
noteseq = 8,
header = '{| class="wikitable"\n!qid !!_ucode !!base !!name1 !!name2 !!link !!label !!note',
item = '|-\n|%s ||%s ||%s ||%s ||%s ||%s ||%s ||%s',
footer = '|}',
},
}
local function listunits(tdata, ulookup)
-- For Module:Convert, make wikitext to list the built-in Wikidata units.
-- Return true, wikitext if successful or return false, t where t is an
-- error message table. Currently, an error return never occurs.
-- The syntax of each unit definition is checked and a note is added if
-- a problem is detected.
local wdunits = tdata.wikidata_units
for _, s in ipairs({ 'base', 'unknown', 'known' }) do
specifications[s].units = collection()
end
local keys, n = {}, 0
for k, v in pairs(wdunits) do
n = n + 1
keys[n] = k
end
table.sort(keys)
for _, key in ipairs(keys) do
local unit = wdunits[key]
local s
if key:match('^Q%d+$') then
if unit.ucode then
s = 'known'
else
s = 'unknown'
end
else
s = 'base'
end
local result = { key }
local spec = specifications[s]
local fields = spec.fields
local note = collection()
for k, v in pairs(unit) do
if fields[k] then
local seq = fields[k].seq
if result[seq] then
note:add('duplicate ' .. k) -- cannot happen since keys are unique
else
result[seq] = v
end
else
note:add('invalid ' .. k)
end
end
for k, v in pairs(fields) do
local seq = v.seq
if result[seq] then
if v.si and not wdunits[result[seq]] then
note:add('need si ' .. result[seq])
end
else
result[seq] = ''
if v.mandatory then
note:add('missing ' .. k)
end
end
end
result[spec.noteseq] = note:join('<br />')
spec.units:add(result)
end
local results = collection()
for _, s in ipairs({ 'base', 'unknown', 'known' }) do
local spec = specifications[s]
results:add("'''" .. spec.title .. "'''")
results:add(spec.header)
local fmt = spec.item
for _, unit in ipairs(spec.units) do
results:add(string.format(fmt, unpack(unit)))
end
results:add(spec.footer)
end
return true, results:join('\n')
end
return { _adjustparameters = adjustparameters, _listunits = listunits }