Skip to content

Commit cc60f13

Browse files
committed
split MapTable into Controller/Types/Lib/Components/Api
1 parent 366705b commit cc60f13

8 files changed

Lines changed: 428 additions & 194 deletions

File tree

‎lua/spec/maptable_parse_spec.lua‎

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
--- Triple Comment to Enable our LLS Plugin
2+
--[[
3+
Unit tests for the pure Lib layer of Module:MapTable.
4+
5+
This is the payoff of splitting MapTable into layers: reading a row and deriving its links used to
6+
live in the same file as the LPDB writes and the redirect lookups, so they could only be reached by
7+
running the whole table. They are pure now, so they can be tested directly, with no I/O mocks.
8+
9+
SetActiveWiki is not a mock, it only puts wikis/trackmania on the module search path.
10+
11+
The end to end behaviour of the same code stays covered through Module:MapTable/Controller.
12+
]]
13+
14+
describe('MapTable Lib', function()
15+
local MapTableParse
16+
17+
setup(function()
18+
SetActiveWiki('trackmania')
19+
MapTableParse = require('Module:MapTable/Lib/Parse')
20+
end)
21+
22+
teardown(function()
23+
SetActiveWiki()
24+
end)
25+
26+
describe('readRows', function()
27+
it('reads the indexed args into rows', function()
28+
local rows = MapTableParse.readRows{
29+
[1] = '{"map":"Stadium","mapper1":"Player One"}',
30+
[2] = '{"map":"Desert"}',
31+
}
32+
33+
assert.are_equal(2, #rows)
34+
assert.are_equal('Stadium', rows[1].map)
35+
assert.are_equal('Player One', rows[1].mapper1)
36+
assert.are_equal('Desert', rows[2].map)
37+
end)
38+
39+
it('reads no rows from empty args', function()
40+
assert.are_equal(0, #MapTableParse.readRows{})
41+
end)
42+
end)
43+
44+
describe('readMappers', function()
45+
it('reads the mapper, author and a prefixes in order', function()
46+
local mappers = MapTableParse.readMappers{
47+
map = 'Stadium',
48+
mapper1 = 'Player One',
49+
author2 = 'Player Two',
50+
a3 = 'Player Three',
51+
}
52+
53+
assert.are_equal(3, #mappers)
54+
assert.are_equal(1, mappers[1].index)
55+
assert.are_equal(2, mappers[2].index)
56+
assert.are_equal(3, mappers[3].index)
57+
assert.are_equal('Player One', mappers[1].displayName)
58+
assert.are_equal('Player Two', mappers[2].displayName)
59+
assert.are_equal('Player Three', mappers[3].displayName)
60+
end)
61+
62+
it('resolves the flag of the row', function()
63+
local mappers = MapTableParse.readMappers{mapper1 = 'Player One', mapper1flag = 'se'}
64+
65+
assert.are_equal('Sweden', mappers[1].flag)
66+
end)
67+
68+
it('leaves the page name unset, because resolving it needs a lookup', function()
69+
local mappers = MapTableParse.readMappers{mapper1 = 'Player One'}
70+
71+
assert.is_nil(mappers[1].pageName)
72+
end)
73+
74+
it('reads no mappers from a row without one', function()
75+
assert.are_equal(0, #MapTableParse.readMappers{map = 'Stadium'})
76+
end)
77+
end)
78+
79+
describe('makeFullLinks', function()
80+
it('builds full links for the row', function()
81+
local links = MapTableParse.makeFullLinks{twitch = 'channel'}
82+
83+
assert.are_equal('https://www.twitch.tv/channel', links.twitch)
84+
end)
85+
86+
it('drops links the row left empty', function()
87+
local links = MapTableParse.makeFullLinks{twitch = 'channel', empty = ''}
88+
89+
assert.is_nil(links.empty)
90+
end)
91+
92+
it('does not turn non-link args into links', function()
93+
local links = MapTableParse.makeFullLinks{map = 'Stadium'}
94+
95+
assert.is_nil(links.map)
96+
end)
97+
end)
98+
end)

‎lua/wikis/trackmania/MapTable.lua‎

Lines changed: 3 additions & 194 deletions
Original file line numberDiff line numberDiff line change
@@ -7,198 +7,7 @@
77

88
local Lua = require('Module:Lua')
99

10-
local Arguments = Lua.import('Module:Arguments')
11-
local Array = Lua.import('Module:Array')
12-
local Json = Lua.import('Module:Json')
13-
local Links = Lua.import('Module:Links')
14-
local Logic = Lua.import('Module:Logic')
15-
local Lpdb = Lua.import('Module:Lpdb')
16-
local Namespace = Lua.import('Module:Namespace')
17-
local Opponent = Lua.import('Module:Opponent')
18-
local PlayerExt = Lua.import('Module:Player/Ext/Custom')
19-
local Table = Lua.import('Module:Table')
10+
local MapTableController = Lua.import('Module:MapTable/Controller')
2011

21-
local Link = Lua.import('Module:Widget/Basic/Link')
22-
local Html = Lua.import('Module:Widget/Html')
23-
local InlinePlayerWidget = Lua.import('Module:Widget/PlayerDisplay/Inline')
24-
local TableWidgets = Lua.import('Module:Widget/Table2/All')
25-
26-
-- Default variant used when building the links of a map
27-
local LINK_VARIANT = 'map'
28-
29-
---@class TrackmaniaMapTableRowArgs: table<string, string?>
30-
---@field map string?
31-
---@field mapper string?
32-
---@field mapperFlag string?
33-
34-
---@class TrackmaniaMapTableMapper: standardPlayer
35-
---@field index integer
36-
37-
local MapTable = {}
38-
39-
---Reads the mapper entries of a single row and resolves their links and flags
40-
---@param row TrackmaniaMapTableRowArgs
41-
---@return TrackmaniaMapTableMapper[]
42-
local function readMappers(row)
43-
---@type TrackmaniaMapTableMapper[]
44-
local mappers = {}
45-
46-
for key, mapper, index in Table.iter.pairsByPrefix(row, {'mapper', 'author', 'a'}, {requireIndex = false}) do
47-
---@type TrackmaniaMapTableMapper
48-
local player = Table.merge(
49-
Opponent.readSinglePlayerArgs{
50-
name = mapper,
51-
link = row[key .. 'link'],
52-
flag = row[key .. 'flag'],
53-
},
54-
{index = index}
55-
)
56-
57-
PlayerExt.populatePageName(player)
58-
player.flag = player.flag or PlayerExt.fetchPlayerFlag(player.pageName)
59-
60-
table.insert(mappers, player)
61-
end
62-
63-
return mappers
64-
end
65-
66-
---Builds the full links of a single map
67-
---@private
68-
---@param mapInput table
69-
---@return {[string]: string}
70-
local function makeFullLinks(mapInput)
71-
return Table.filterByKey(
72-
Links.makeFullLinksForTableItems(Links.transform(mapInput), LINK_VARIANT),
73-
function(_, link) return link ~= '' end
74-
)
75-
end
76-
77-
---Builds the links cell content for a single map
78-
---@private
79-
---@param links {[string]: string}
80-
---@return Renderable[]
81-
local function makeLinksDisplay(links)
82-
return Array.interleave(
83-
Array.extractValues(Table.map(links, function(key, link)
84-
return key, Link{
85-
link = link,
86-
children = Links.makeIcon(Links.removeAppendedNumber(key), 25),
87-
linktype = 'external',
88-
}
89-
end), Table.iter.spairs),
90-
' '
91-
)
92-
end
93-
94-
---Builds the mapper cell content for a single map
95-
---@private
96-
---@param mappers TrackmaniaMapTableMapper[]
97-
---@return Renderable[]
98-
local function makeMapperDisplay(mappers)
99-
return Array.interleave(
100-
Array.map(mappers, function(mapper) return InlinePlayerWidget{player = mapper} end),
101-
Html.Br{}
102-
)
103-
end
104-
105-
---Creates an LPDB map record per map, as `map` datapoints
106-
---@param rows TrackmaniaMapTableRowArgs[]
107-
---@param mappers TrackmaniaMapTableMapper[][]
108-
---@param links {[string]: string}[]
109-
local function createLpdbEntry(rows, mappers, links)
110-
if not Namespace.isMain() or Lpdb.isStorageDisabled() then
111-
return
112-
end
113-
114-
Array.forEach(rows, function(row, rowIndex)
115-
local mapName = row.map
116-
if Logic.isEmpty(mapName) then
117-
return
118-
end
119-
120-
local extradata = {}
121-
for _, mapper in ipairs(mappers[rowIndex]) do
122-
extradata['author' .. mapper.index] =
123-
mapper.pageName and mapper.pageName:gsub(' ', '_') or ''
124-
extradata['author' .. mapper.index .. 'dn'] = mapper.displayName
125-
extradata['author' .. mapper.index .. 'flag'] = mapper.flag or ''
126-
end
127-
128-
local rowLinks = links[rowIndex]
129-
if Table.isNotEmpty(rowLinks) then
130-
extradata.links = rowLinks
131-
end
132-
133-
mw.ext.LiquipediaDB.lpdb_datapoint('map_' .. mapName, Json.stringifySubTables({
134-
name = mapName,
135-
type = 'map',
136-
extradata = extradata,
137-
}))
138-
end)
139-
end
140-
141-
---@param rows TrackmaniaMapTableRowArgs[]
142-
---@param mappers TrackmaniaMapTableMapper[][]
143-
---@param links {[string]: string}[]
144-
---@return Renderable
145-
local function makeBody(rows, mappers, links)
146-
return TableWidgets.TableBody{
147-
children = Array.map(rows, function(row, index)
148-
return TableWidgets.Row{
149-
children = {
150-
TableWidgets.Cell{children = makeMapperDisplay(mappers[index])},
151-
TableWidgets.Cell{children = row.map},
152-
TableWidgets.Cell{
153-
classes = {'plainlinks'},
154-
children = makeLinksDisplay(links[index]),
155-
},
156-
},
157-
}
158-
end),
159-
}
160-
end
161-
162-
---@return Renderable
163-
local function makeHeader()
164-
return TableWidgets.TableHeader{
165-
children = {
166-
TableWidgets.Row{
167-
children = {
168-
TableWidgets.CellHeader{children = 'Author'},
169-
TableWidgets.CellHeader{children = 'Map'},
170-
TableWidgets.CellHeader{children = 'Links'},
171-
},
172-
},
173-
},
174-
}
175-
end
176-
177-
-- Module entry point
178-
---@param frame Frame
179-
---@return Renderable
180-
function MapTable.run(frame)
181-
local args = Arguments.getArgs(frame)
182-
183-
---@type TrackmaniaMapTableRowArgs[]
184-
local rows = Array.map(
185-
Array.mapIndexes(function(index) return args[index] end),
186-
Json.parseIfString
187-
)
188-
189-
local mappers = Array.map(rows, readMappers)
190-
local links = Array.map(rows, makeFullLinks)
191-
192-
local renderedTable = TableWidgets.Table{
193-
children = {
194-
makeHeader(),
195-
makeBody(rows, mappers, links),
196-
},
197-
}
198-
199-
createLpdbEntry(rows, mappers, links)
200-
201-
return renderedTable
202-
end
203-
204-
return MapTable
12+
--- see Module:MapTable/Controller for the entry point
13+
return MapTableController
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
-- @Liquipedia
3+
-- page=Module:MapTable/Api/Mappers
4+
--
5+
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
6+
--
7+
8+
local Lua = require('Module:Lua')
9+
10+
local Array = Lua.import('Module:Array')
11+
local PlayerExt = Lua.import('Module:Player/Ext/Custom')
12+
13+
local MapTableMappers = {}
14+
15+
---Resolves the page name of a mapper and their flag
16+
---@param mapper TrackmaniaMapTableMapper
17+
---@return TrackmaniaMapTableMapper
18+
local function resolveMapper(mapper)
19+
PlayerExt.populatePageName(mapper)
20+
mapper.flag = mapper.flag or PlayerExt.fetchPlayerFlag(mapper.pageName)
21+
22+
return mapper
23+
end
24+
25+
---Resolves every mapper, keeping the order they were read
26+
---@param mappers TrackmaniaMapTableMappers
27+
---@return TrackmaniaMapTableMappers
28+
function MapTableMappers.resolveMappers(mappers)
29+
return Array.map(mappers, function(rowMappers)
30+
return Array.map(rowMappers, resolveMapper)
31+
end)
32+
end
33+
34+
return MapTableMappers
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
-- @Liquipedia
3+
-- page=Module:MapTable/Api/Store
4+
--
5+
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute
6+
--
7+
8+
local Lua = require('Module:Lua')
9+
10+
local Array = Lua.import('Module:Array')
11+
local Json = Lua.import('Module:Json')
12+
local Logic = Lua.import('Module:Logic')
13+
local Lpdb = Lua.import('Module:Lpdb')
14+
local Namespace = Lua.import('Module:Namespace')
15+
local Table = Lua.import('Module:Table')
16+
17+
local MapTableStore = {}
18+
19+
---Builds the extradata of a single map
20+
---@param mappers TrackmaniaMapTableMapper[]
21+
---@param links {[string]: string}?
22+
---@return table
23+
local function buildExtradata(mappers, links)
24+
local extradata = {}
25+
for _, mapper in ipairs(mappers) do
26+
extradata['author' .. mapper.index] =
27+
mapper.pageName and mapper.pageName:gsub(' ', '_') or ''
28+
extradata['author' .. mapper.index .. 'dn'] = mapper.displayName
29+
extradata['author' .. mapper.index .. 'flag'] = mapper.flag or ''
30+
end
31+
32+
if Table.isNotEmpty(links) then
33+
extradata.links = links
34+
end
35+
36+
return extradata
37+
end
38+
39+
---Creates an LPDB map record per map, as `map` datapoints
40+
---@param rows TrackmaniaMapTableRows
41+
---@param mappers TrackmaniaMapTableMappers
42+
---@param links TrackmaniaMapTableLinks
43+
function MapTableStore.storeMaps(rows, mappers, links)
44+
if not Namespace.isMain() or Lpdb.isStorageDisabled() then
45+
return
46+
end
47+
48+
Array.forEach(rows, function(row, rowIndex)
49+
local mapName = row.map
50+
if Logic.isEmpty(mapName) then
51+
return
52+
end
53+
54+
mw.ext.LiquipediaDB.lpdb_datapoint('map_' .. mapName, Json.stringifySubTables({
55+
name = mapName,
56+
type = 'map',
57+
extradata = buildExtradata(mappers[rowIndex], links[rowIndex]),
58+
}))
59+
end)
60+
end
61+
62+
return MapTableStore

0 commit comments

Comments
 (0)