Editing Module:DPLlua

Warning: You are not logged in. Once you make an edit, a temporary account will be created for you. Learn more. Log in or create an account to continue receiving notifications after this account expires, and to access other features.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision Your text
Line 2: Line 2:
local dpl = {}
local dpl = {}
local libraryUtil = require( 'libraryUtil' )
local libraryUtil = require( 'libraryUtil' )
local hasContent = require( 'Module:Paramtest' ).has_content
local checkType = libraryUtil.checkType
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
Line 32: Line 31:
-- Also custom function for speed
-- Also custom function for speed
local function trim( str )
local function trim( str )
return (string.gsub( str, '^%s+', '' ):gsub( '%s+$', '' ))
return string.match( str, '^%s*(.-)%s*$' )
end
 
local function mergeItem( tbl, key, item )
if type( tbl[key] ) == 'table' and type( item ) == 'table' then
for k in pairs( tbl[key] ) do
mergeItem( tbl[key], k, item[k] )
end
elseif type( tbl[key] ) == 'table' then
table.insert( tbl[key], item )
else
tbl[key] = { tbl[key], item }
end
end
end


local escapeChars = {
local escapeChars = {
['{'] = '{',
['{'] = '{',
['❴'] = '{', -- Wtf dpl...
['}'] = '}',
['}'] = '}',
['❵'] = '}',
['['] = '[',
['['] = '[',
[']'] = ']',
[']'] = ']',
Line 56: Line 45:
}
}
local function escape( str )
local function escape( str )
return (string.gsub( str, '[{}%[%]|%-]', escapeChars ))
-- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow.
str = string.gsub( str, '[{}%[%]|%-]', escapeChars ):gsub( '\226\157[\180\181]', escapeChars )
return str
end
end


Line 68: Line 60:
}
}
local function unEscape( str )
local function unEscape( str )
return (string.gsub( str, '&#%d+;', unEscapeChars ))
str = string.gsub( str, '&#%d+;', unEscapeChars )
end
return str
 
local function fixCurlyBrackets( str )
-- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow.
return (string.gsub( str, '\226\157[\180\181]', { ['❴'] = '{', ['❵'] = '}' } ))
end
end


Line 105: Line 92:
'suppresserrors',
'suppresserrors',
'noresultsfooter',
'noresultsfooter',
'format',
'format'
'groupMultiTemplateResults'
}
}


Line 115: Line 101:


local function formatInclude( query )
local function formatInclude( query )
checkTypeForNamedArg( 'Module:DPLlua.ask', 'include', query, 'string' )
checkTypeForNamedArg( 'include', 'Module:DPLlua.ask', query, 'string' )
query = split( query, ',', true )
query = split( query, ',', true )
local includedParamNames = {}
local includedParamNames = {}
local sectionAttributes = {}


for i = 1, #query do
for i = 1, #query do
if query[i]:match( '%b{}' ) then -- Check if we are including a template
if query[i]:match( '%b{}' ) then -- Check if we are including a template
local templateName, extra = query[i]:match( '{(.-)[¦|}](.*)' )
local templateName, params = query[i]:match( '{(.-)[¦|}]([^,]*)' )
if hasContent( extra ) then
if params:find( '%S' ) then
local phantomTemplateName = extra:match( '^(.-)}' ) or extra:match( '^[./].+' )
params:gsub( '^:%-', '' )
local phantomTemplatePrefix = extra:match( '^(.-)}' ) and '' or templateName
query[i] = string.format( '{%s}%s', templateName, params )
local params = extra:gsub( '^.-}', '' ):gsub( '^[./].+', '' ):gsub( ':%-', '' )
local sur = hasContent( phantomTemplateName ) and ('¦' .. phantomTemplatePrefix .. phantomTemplateName) or ''
query[i] = string.format( '{%s%s}%s', templateName, sur, params )


if hasContent( phantomTemplateName ) then
for param in params:gmatch( ':([^:]*)' ) do
table.insert( includedParamNames, { name=phantomTemplatePrefix..phantomTemplateName, isTemplate=true, hasPhantomTemplate=true } )
param = trim( param )
table.insert( sectionAttributes, { hasPhantomTemplate=true } )
table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } )
else
for param in params:gmatch( ':([^:]*)' ) do
param = trim( param )
table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } )
end
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
end
else
else
query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template
query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template
table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } )
table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
end
else
else
table.insert( includedParamNames, { name=trim( query[i] ) } )
table.insert( includedParamNames, { name=trim( query[i] ) } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
end
end
end


return table.concat( query, ',' ), includedParamNames, sectionAttributes
return table.concat( query, ',' ), includedParamNames
end
end


Line 160: Line 135:
local usesInclude = false
local usesInclude = false
local includedParamNames = {}
local includedParamNames = {}
local sectionAttributes
query.count = nil
query.count = nil
query.offset = nil
query.offset = nil


-- Use table format so we can place dataContentMarkers around each included parameter. The secseparator
-- We use table format when the include parameter is used to make sure we can
-- is needed to add dataContentMarkers when a phantom template is used
-- differentiate between the results in case more than one item is included
local dplStringInclude =
local dplStringInclude =
[=[
[=[
Line 174: Line 148:
|%s
|%s
|table=,
|table=,
|listseparators=,\n¦-\n¦[[%%PAGE%%¦]],,
|tablerow=%s
|tablerow=%s
|secseparators=%s
}}]=]
}}]=]


Line 198: Line 170:
for k, v in pairs( query ) do
for k, v in pairs( query ) do
if k == 'include' then
if k == 'include' then
v, includedParamNames, sectionAttributes = formatInclude( v )
v, includedParamNames = formatInclude( v )
usesInclude =  true
usesInclude =  true
end
end
Line 212: Line 184:


if usesInclude then
if usesInclude then
local secseparators = ''
for _, v in ipairs( sectionAttributes ) do
if v.hasPhantomTemplate then
-- Phantom templates need this because they ignore tablerow formatting
secseparators = secseparators .. '¶¦' .. dataContentMarker .. ',' .. dataContentMarker .. ','
else
secseparators = secseparators .. '¶¦,,'
end
end
table.insert( queries, string.format(
table.insert( queries, string.format(
dplStringInclude,
dplStringInclude,
Line 227: Line 189:
offset,
offset,
table.concat( params, '\n|' ),
table.concat( params, '\n|' ),
string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ),
string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames )
secseparators
) )
) )
else
else
Line 244: Line 205:


table.insert( allIncludedParamNames, includedParamNames )
table.insert( allIncludedParamNames, includedParamNames )
return table.concat( queries )
return table.concat( queries )
end
end


local function toTable( query, groupMultiTemplateResults )
local function toTable( query )
local includedParamNames = table.remove( allIncludedParamNames, 1 )
local includedParamNames = table.remove( allIncludedParamNames, 1 )
local usesInclude = #includedParamNames > 0
local usesInclude = #includedParamNames > 0
Line 259: Line 221:


if usesInclude then
if usesInclude then
query = query:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end ) -- Unstrip nowiki so we can clean their content
query = mw.text.unstripNoWiki( query )
query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape )
query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape )
query = query:gsub( '{|.-|%-', '' ) -- Remove the header of the table
-- Replace the footer of the table width a row indicator. This effectively
-- combines the output of multiple dpl queries when count > 500
query = query:gsub( '|}', '|-' )
end
end


Line 266: Line 234:


for _, v in ipairs( query ) do
for _, v in ipairs( query ) do
if hasContent( v ) and not v:find( '^@@' ) then
if v:find( '%S' ) and not v:find( '^@@' ) then
v = trim( v )
v = trim( v )
local title = v:match( '^|%[%[(.-)|' )
local title = v:match( '^|%[%[(.-)|' )
Line 276: Line 244:
end
end
else
else
-- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) their results are separated by a pipe
-- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) its results are separated by a pipe
rawDataList = split( rawDataList, '|', true )
rawDataList = split( rawDataList, '|', true )
local cleanedDataList = {}
local cleanedDataList = {}


for _incIndex, dataItem in ipairs( rawDataList ) do
for incIndex, dataItem in ipairs( rawDataList ) do
local incIndex = ((_incIndex - 1) % #includedParamNames) + 1 -- Needed in case the same template appears multiple times on the same page
dataItem = unEscape( dataItem )
dataItem = unEscape( dataItem )
-- When we include an entire template we use the %ARGS% parameter supplied by dpl.
-- However all | characters are repaced with §, e.g.:
-- §nameLessParam
-- §param = text [[wowee§link text]]
-- §param2 = text {{something§something else}}
dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end )
dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki
dataItem = trim( dataItem )
dataItem = trim( dataItem )


if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template
if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template
-- When we include an entire template we use the %ARGS% parameter supplied by dpl.
-- However all | characters are repaced with §, e.g.:
-- §namelessParam
-- §param = text [[wowee§link text]]
-- §param2 = text {{something§something else}}
dataItem = dataItem:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end )
dataItem = mw.text.unstripNoWiki( dataItem ) -- Unstrip nowiki so we can clean their content
dataItem = fixCurlyBrackets( dataItem ) -- When using the %ARGS% dpl parameter, curly brackets are replaced with ❴ (U+2774) and ❵ (U+2775)
dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end )
dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki
local _dataItem = {}
local _dataItem = {}


Line 315: Line 279:
end
end


local dataListIndex = groupMultiTemplateResults and 1 or math.ceil( _incIndex / #includedParamNames )
if includedParamNames[ incIndex ].isTemplate and not includedParamNames[ incIndex ].includeAll then -- This means there was an include in the form 'include = {template}:param'
if
includedParamNames[ incIndex ].isTemplate and
not includedParamNames[ incIndex ].includeAll and
not includedParamNames[ incIndex ].hasPhantomTemplate
then -- This means there was an include in the form 'include = {template}:param'
local templateName = includedParamNames[ incIndex ].name
local templateName = includedParamNames[ incIndex ].name
local paramName = includedParamNames[ incIndex ].param
local paramName = includedParamNames[ incIndex ].param
paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails
paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
cleanedDataList[ templateName ] = cleanedDataList[ templateName ] or {}
cleanedDataList[ dataListIndex ][ templateName ] = cleanedDataList[ dataListIndex ][ templateName ] or {}
cleanedDataList[ templateName ][ paramName ] = dataItem
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ][ templateName ], paramName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ][ paramName ] = dataItem
end
else
else
local templateName = includedParamNames[ incIndex ].name
cleanedDataList[ includedParamNames[ incIndex ].name ] = dataItem
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ], templateName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ] = dataItem
end
end
end
end
end


if title and title ~= '' then
if title and title ~= '' then
for _, v in ipairs( cleanedDataList ) do
table.insert( res, { title=title, include=cleanedDataList } )
table.insert( res, { title=title, include=v } )
end
end
end
end
end
Line 359: Line 303:
-- Combinig multiple dpl queries yields better performance than doing them sequentially
-- Combinig multiple dpl queries yields better performance than doing them sequentially
function dpl.ask( ... )
function dpl.ask( ... )
local formatTime = os.clock()
local queries = { ... }
local queries = { ... }
local wantsGrouping = {}


for i = 1, #queries do
for i = 1, #queries do
checkType( 'Module:DPLlua.ask', i, queries[i], 'table' )
checkType( 'Module:DPLlua.ask', i, queries[i], 'table' )
table.insert( wantsGrouping, queries[i].groupMultiTemplateResults or false )
removeFormattingSettings( queries[i] )
removeFormattingSettings( queries[i] )
queries[i] = formatDpl( queries[i] )
queries[i] = formatDpl( queries[i] )
end
end
formatTime = os.clock() - formatTime


local DPLtime = os.clock()
queries = table.concat( queries, '$@µ@$' )
queries = table.concat( queries, '$@µ@$' )
local time = os.clock()
queries = mw.getCurrentFrame():preprocess( queries )
queries = mw.getCurrentFrame():preprocess( queries )
time = os.clock() - time
queries = split( queries, '$@µ@$', true )
queries = split( queries, '$@µ@$', true )
DPLtime = os.clock() - DPLtime


for i = 1, #queries do
for i = 1, #queries do
local parseTime = os.clock()
queries[i] = toTable( queries[i] )
queries[i] = toTable( queries[i], wantsGrouping[i] )
queries[i].time = time
parseTime = os.clock() - parseTime
queries[i]['DPL time'] = DPLtime
queries[i]['Parse time'] = math.floor( (formatTime + parseTime) * 1e5 ) / 1e5 -- os.clock() has a resolution of 10µs
end
end


return unpack( queries )
return unpack( queries )
end
end
-- function dpl.test()
-- local time = os.clock()
-- local a, b = dpl.ask({
--    namespace = 'Module',
--    linksto = 'Module:Chart data',
--    distinct = 'strict',
--    ordermethod = 'title',
--    nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
-- ignorecase = 'true',
-- allowcachedresults = false
-- },{
--    namespace = 'Module',
--    linksto = 'Module:Enum',
--    distinct = 'strict',
--    ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Enum',
--    ignorecase = 'true',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
-- local a, b = dpl.ask({
--    namespace = 'Module',
--    linksto = 'Module:Chart data',
--    distinct = 'strict',
--    ordermethod = 'title',
--    nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
--    ignorecase = 'true',
-- allowcachedresults = false
-- },{
-- namespace = '',
-- ignorecase = 'true',
-- uses = 'Template:Infobox Recipe',
-- count = 50,
-- include = '{Infobox Recipe},{Infobox Item}',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
-- local a = dpl.ask{
-- namespace = '',
-- uses = 'Template:Infobox Recipe',
-- include = '{Infobox Recipe}:skill:name,{Infobox Item}:update,{Infobox Item|test}',
-- count = 50,
-- ordermethod = 'title',
-- }
-- mw.logObject(a)
-- local q = dpl.ask{
-- uses = "Template:Collections table",
-- category = "Archaeology collections",
-- -- include = "{Infobox Collection}:reward,{Collections table}:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15",
-- include = "{Infobox Collection}:reward,{Collections table}",
-- count = 100
-- }
-- mw.logObject(q)
-- local q = dpl.ask{
-- namespace = "",
-- uses = "Template:Infobox Spell",
-- notcategory = {"Removed content", "Removed spells"},
-- nottitlematch = {"Enchant Crossbow Bolt", "Storm of Armadyl"},
-- include = "{Infobox Spell}",
-- }
-- mw.logObject(q)
-- local list = dpl.ask{
-- namespace = 'Template',
-- uses = 'Template:Navbox',
-- ordermethod = 'title',
-- include = '{Navbox}:gtitle1:gtitle2',
-- count = 1,
-- offset = 3
-- }
-- mw.logObject(list)
-- local list = dpl.ask{
-- namespace = 'User',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2|User:CephHunter/Sandbox/test3},{User:CephHunter/Sandbox/test3}:1',
-- }
-- mw.logObject(list)
-- mw.logObject(dpl.ask{
-- namespace = 'User',
-- ignorecase = 'true',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2}'
-- })
-- mw.logObject(dpl.ask{
-- namespace = 'Module',
-- uses = 'Template:Helper module',
-- titlematch = '%/doc',
-- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%',
-- ordermethod = 'title',
-- include = '{Helper module}, {Helper module}:example',
-- count = 1,
-- offset = 13
-- })
-- mw.logObject(dpl.ask{
--        namespace = 'Module',
--        titlematch = 'Chart data|Absorbative calculator',
--        nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%|%/doc|DPLlua%',
--        ordermethod = 'title',
--        include = '%0'
-- })
-- mw.logObject(dpl.ask{
--        uses = 'Template:Collections table',
--        include = '{Collections table}',
--        count = 5
-- })
-- mw.log(os.clock()-time)
-- end


return dpl
return dpl
-- </nowiki>
-- </nowiki>
Please note that all contributions to The Deadlock Wiki are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see Deadlock:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template

Page included on this page: