Module:Sandbox/trappist the monk/nts: Difference between revisions
imported>Legoktm Replace Module:No globals with require( "strict" ) |
(No difference)
|
Latest revision as of 21:12, 23 October 2022
Lua error at line 187: attempt to index field 'wikibase' (a nil value).
require ('strict'); -- alarm when global variables etc are used
local nts = require ('Module:Canada NTS'); -- for extents_from_grid(), nts_series_validate, nts_are_validate, nts_sheet_validate
local data = mw.loadData ('Module:Canada NTS/data'); -- load the ~/data module
--[[--------------------------< W I K I D A T A _ L A T _ L O N G _ G E T >------------------------------------
returns latitude and longitude from wikidata for <qid>; nil else
]]
local function wikidata_lat_lon_get (qid)
if qid then
local value_t = mw.wikibase.getBestStatements (qid, 'P625')[1]; -- attempt to get P625; nil when article does not have P625
if value_t then
value_t = value_t.mainsnak.datavalue.value; -- point to the value table
return value_t.latitude, -1.0 * value_t.longitude; -- return coordinates from value_t; longitude normalized
end
end
end
--[[--------------------------< T A B B I N G >----------------------------------------------------------------
return the number of tabs necessary to more-or-less position comments at column 80 (the right-side margin line
in the wiki code editor)
]]
local function tabbing (str)
return math.ceil ((80 - 4 - str:len()) / 4); -- the -4 because every line begins with a tab character
end
--[[--------------------------< S O R T >----------------------------------------------------------------------
sort by keys; ascending order numerically by series then by area (alpha sort) then numerically by sheet
]]
local function sort (a, b)
local a_key_series, a_key_area, a_key_sheet = a:match ('(%d+)(%u)(%d*)'); -- extract series, area, sheet NTS id parts from <a>
local b_key_series, b_key_area, b_key_sheet = b:match ('(%d+)(%u)(%d*)'); -- extract series, area, sheet NTS id parts from <b>
a_key_series = tonumber (a_key_series); -- convert numerical parts of key from <a> to numbers for comparison
a_key_sheet = tonumber (a_key_sheet); -- nil when <a_key_sheet> is empty string
a_key_sheet = a_key_sheet and a_key_sheet or 0 -- optional so when omitted set to 0 for comparison
b_key_series = tonumber (b_key_series); -- convert numerical parts of key from <a> to numbers for comparison
b_key_sheet = tonumber (b_key_sheet); -- nil when <b_key_sheet> is empty string
b_key_sheet = b_key_sheet and b_key_sheet or 0 -- optional so when omitted set to 0 for comparison
if a_key_series ~= b_key_series then -- do the comparisons; by series first
return a_key_series < b_key_series;
elseif a_key_area ~= b_key_area then -- then by area
return a_key_area < b_key_area;
else
return a_key_sheet < b_key_sheet; -- and lastly by sheet
end
end
--[[--------------------------< L A T _ B O U N D S _ C H E C K >----------------------------------------------
is <lat> same as or north of <south> and is <lat> same as or south of <north>?
returns direction 'north' or 'south' when <lat> out of bounds; nil else
]]
local function lat_bounds_check (lat, north, south)
if lat < south then
return 'south'; -- out of bounds south of <south>
elseif lat > north then
return 'north'; -- out of bounds north of <north>
end
end
--[[--------------------------< L O N _ B O U N D S _ C H E C K >----------------------------------------------
is <lon> same as or east of <west> and is <lat> same as or west of <east>?
returns direction 'east' or 'west' when <lon> out of bounds; nil else
]]
local function lon_bounds_check (lon, west, east)
if lon < east then
return 'east'; -- out of bounds east of <east>
elseif lon > west then
return 'west'; -- out of bounds west of <west>
end
end
--[[--------------------------< I S _ I N _ B O U N D S >------------------------------------------------------
get map extents using series, area, sheet. check to see that lat/lon fall within the map extents.
returns empty string for concatenation when lat/lon fall within map extents; an error message else
only one error mesage is returned; if both <lat> and <lon> are out of bounds, this function returns an error
message for only one of them
because series, area, sheet are taken from Module:Canada NTS/data, they are presumed to be correct
]]
local function is_in_bounds (series, area, sheet, lat, lon)
local extents_t = nts.extents_from_grid (tonumber(series), area, tonumber(sheet)); -- fetch extents for this nts key
local lat_fail, lon_fail; -- flags
local north, west, south, east; -- map extents
if '' == sheet then -- is this searies, area, sheet an area map?
north, west, south, east = extents_t.area_north, extents_t.area_west, extents_t.area_south, extents_t.area_east;
lat_fail = lat_bounds_check (lat, north, south);
lon_fail = lon_bounds_check (lon, west, east);
else -- here when sheet map
north, west, south, east = extents_t.north, extents_t.west, extents_t.south, extents_t.east;
lat_fail = lat_bounds_check (lat, north, south);
lon_fail = lon_bounds_check (lon, west, east);
end
if lat_fail or lon_fail then -- build error message
if 'north' == lat_fail then
return string.format ('P625 %s latitude out of bounds: WD lat/lon: <%s>,%s (NW: <%s>,%s / SE: %s,%s)',
lat_fail, lat, lon, north, west, south, east);
elseif 'south' == lat_fail then
return string.format ('P625 %s latitude out of bounds: WD lat/lon: <%s>,%s (NW: %s,%s / SE: <%s>,%s)',
lat_fail, lat, lon, north, west, south, east);
elseif 'west' == lon_fail then
return string.format ('P625 %s longitude out of bounds: WD lat/lon: %s,<%s> (NW: %s,<%s> / SE: %s,%s)',
lon_fail, lat, lon, north, west, south, east);
elseif 'east' == lon_fail then
return string.format ('P625 %s longitude out of bounds: WD lat/lon: %s,<%s> (NW: %s,%s / SE: %s,<%s>)',
lon_fail, lat, lon, north, west, south, east);
end
end
return ''; -- in bounds so return empty string message for concatenation
end
--[[--------------------------< M A I N >----------------------------------------------------------------------
fetch <map_series> entries from Module:Canada NTS/data. For each of those, attempt to get qid that matches the
en.wiki article title from wikidata. Replace article title with the qid, sort and make all pretty like for
manual replacement in ~/data.
to use the results of this function, Module:Canada NTS requires support for qids in lieu of article names which,
as of 2022-04-12, does not yet exist
This function may be called from an invoke or from the debug console
<frame> is a text string when called from debug console:
=p.main ('92')
{{#invoke:Sandbox/trappist the monk/nts|main|94}}
]]
local function main (frame)
local map_series; -- number of the series that we are operating on; for invokes, this is only number or start of a range
local map_series_end; -- for invokes only; end of a range of map series
local invoked;
if 'table' == type (frame) then
map_series = frame.args[1]; -- for an invoke
if frame.args[2] then
map_series_end = frame.args[2];
end
invoked = true; -- flag used to modify final output rendering
else
map_series = frame; -- when called from the debug console
end
local temp_t = {} -- output goes in this sequence table until rendering
for k, v in pairs (data) do -- for each entry in the data mofule
local series, area, sheet = k:match ('^(%d+)(%u)(%d*)'); -- fetch series, area, sheet from the entry's key
if tonumber(series) >= tonumber(map_series) and tonumber(series) <= tonumber(map_series_end or map_series) then -- when this map is one of the map series we're looking for
local map_title_parts = mw.text.split (v, '|'); -- extract an article title
local qid = mw.wikibase.getEntityIdForTitle (map_title_parts[1]); -- does this article title have a wikidata entry
local lat, lon = wikidata_lat_lon_get (qid); -- attempt to get P625 lat/lon from wikidata's entry for the article title
local bounds_msg = ''; -- gets an error message if lat/lon from wikidata not within bounds of NTS map
if qid and lat then -- when article title has wikidata entry an wikidata has P625 (latitude/longitude)
bounds_msg = is_in_bounds (series, area, sheet, lat, lon); -- empty string when in bounds; message else
elseif qid then -- lat can be nil when qid points to dab page or article does not have P625
bounds_msg = string.format ('%s missing P625', qid); -- no lat/lon so no P625
end
local str;
if not qid then -- when article title doesn't have a wikidata entry
str = string.format ('\t["%s"] = "%s",', k, v); -- mimic the original
elseif not lat then -- has qid but does not have P625
str = string.format ('["%s"] = "%s",', k, v); -- mimic the original + bounds_msg
str = string.format ('\t%s%s-- %s', str, string.rep ('\t', tabbing (str)), bounds_msg);
elseif map_title_parts[2] then -- for piped article links
str = string.format ('["%s"] = "%s|%s",', k, qid, map_title_parts[2]);
str = string.format ('\t%s%s-- %s; %s', str, string.rep ('\t', tabbing (str)), map_title_parts[1], bounds_msg);
else -- map name same as en.wiki article title
str = string.format ('["%s"] = "%s",', k, qid, map_title_parts[1]);
str = string.format ('\t%s%s-- %s; %s', str, string.rep ('\t', tabbing (str)), map_title_parts[1], bounds_msg);
end
if invoked then -- when this function called through an invoke
str = str:gsub ('\t', '	') -- replace plain-text tabs with html numeric entities
end
table.insert (temp_t, str); -- save
end
end
table.sort (temp_t, sort); -- ascending numerical sort by key (NTS id)
for i=#temp_t, 1, -1 do -- working backwards through the table
if temp_t[i]:match ('%d+%u"%]') then -- if this key is an area key (no sheet)
table.insert (temp_t, i, ''); -- insert an empty string to separate area-from-area
elseif i > 1 and temp_t[i]:match ('%["(%d+)') ~= temp_t[i-1]:match ('%["(%d+)') then -- because some series list don't begin with area maps (15 for example)
table.insert (temp_t, i, ''); -- insert an empty string to separate area-from-area
end
end
if invoked then -- when this function called through an invoke
return table.concat ({'<pre>', table.concat (temp_t, '<br />'),'</pre>'}); -- concatenate into a big string using <br /> tags and wrapped in <pre>...</pre> tagsand done
else
return table.concat (temp_t, '\n'); -- concatenate into a big string using plain-text newlines and done
end
end
--[[--------------------------< N T S _ K E Y _ V A L I D A T E >----------------------------------------------
debug console function to makes sure that all keys in Module:Canada NTS/data have the correct form
=p.nts_key_validate()
]]
local function nts_key_validate()
for k, _ in pairs (data) do
local series, area, sheet = k:match ('^(%d+)(%u)(%d*)$');
if not series then
return '<span style="color:#d33">invalid key: ' .. k .. '</span>';
end
if not nts.nts_series_validate (tonumber(series)) then
return '<span style="color:#d33">invalid series: ' .. k .. '</span>';
end
if not nts.nts_area_validate (tonumber(series), area) then
return '<span style="color:#d33">invalid area: ' .. k .. '</span>';
end
if '' ~= sheet and not nts.nts_sheet_validate (tonumber(sheet)) then
return '<span style="color:#d33">invalid sheet: ' .. k .. '</span>';
end
end
return 'keys are valid';
end
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return {
main = main,
nts_key_validate = nts_key_validate,
}