模組:沙盒/Artoria2e5/Infobox artist
本模块用于执行{{藝人}}和{{Infobox artist}}模板,请到模板页阅读具体用法。
贡献指南
目前这个模板最重要的事情就是要抄参数填参数。常用的语法和翻译结果如下所列:
-- 帮手函数
local function _(str)
if str ~= nil and str ~= '' then
return str
else
return nil
end
end
-- 这里演示给定参数调用模板 func 的方法,也是给下面 {{func}} 铺垫
local function func(args)
return frame:expandTemplate{title = 'func', args = args}
end
--[[
Lua -- MediaWiki
]]--
_(a) or _(b) or _(c) or '' -- {{{a|{{{b|{{{c|}}}}}}}}}
_(foo) or '{{{foo}}}' -- {{{foo}}}
_(foo) and 'a' or 'b' -- {{#if:{{{foo|}}}|a|b}}
_(foo):lower() -- {{lc:{{{foo|}}}}}
func({ -- {{func
["1"] = 'anon_1', -- | anon_1
["k"] = 'v', -- | k = v
["2"] = 'anon_2' -- | anon_2 <!-- | 2 = anon_2 -->
}) -- }}
当然,由于我们处理的是实际传来的参数,其实还是要用args['a']
获取参数,而不是处理现有的变量a
。像ifeq
这样的解析器函数其实也不难,看手册就好了。至于Lua语言的语法,这个官方自有教程,也不难。
arg_aliases
如果表格key部分的参数查找args
找不到,那么会按照接下来key指向的备选列表一个个寻找候选内容。也就是说:
["foo"] = {"某", "baaar", "baz"}, -- 对应于 {{{foo|{{{某|{{{baaar|{{{baz|}}}}}}}}}}}}
多换几处,是不是整洁多了?
只可在模板中的所有对某变量的引用都以同种顺序出现时在arg_aliases
加入内容。按照前面对此功能的描述,你很容易就会想通一件事——以后取这套变量,只能用头上作为key的那个字串的名字取,否则就得不到后备查找的加成。
实现上,这个模块用Lua metatable(元表)在args
上面多玩了一层,实现了按照arg_aliases
一个个顺序找候选参数。Lua允许给表格添加一个元表属性,决定特定函数的行为。例如,__index(table, key)
这个函数,会在查找不到table[key]
的时候蹦出来继续尝试查找。
现在我们一步步把注释为“magic”的地方拆开看:
local oldArgsMeta = getmetatable(args) or {} -- 保留旧 metatable。MediaWiki 传入的参数列表据说是用了 metatable。
local newArgsMeta = {} -- 准备一个新的。
for k, v in ipairs(oldArgsMeta) do -- 把旧的都复制过去。之所以不用旧的是因为担心可能只读。
newArgsMeta[k] = v
end
newArgsMeta.__index = function (t, k) -- 开始定义新的 __index 函数。
if oldArgsMeta.__index ~= nil then -- 如果旧的里面有 __index(这里旧的能在这个函数里面用到是因为 Lua 的闭包(closure))
local val = oldArgsMeta.__index(t, k) -- 我们试着用一下
if val ~= nil then -- 如果取到了
return val -- 那就是它了,返回(return)就好
end
end
for _, v in ipairs(arg_aliases[k] or {}) do -- 对于每个在 arg_aliases 里面查到的 k 的后备 v
if t[v] ~= nil and t[v] ~= '' then -- 如果取到了 t[v] 且非空字符串(后者是 MediaWiki 模板参数的要求)
return t[v] -- 就是它了
end
end
return nil -- 没找着
end
setmetatable(args, newArgsMeta) -- 把新的 metatable 套上去,完事儿
这个实现有趣的地方在于t[v]
这里本身还有可能再回到__index
函数,也就是说之前的arg_aliases
可以有递归查找的结构。
--[[ Work in progress:
* [ ] Fill up logic
* [ ] Fill up aliases
]]--
-- This module implements {{藝人}} and {{Infobox artist}}.
-- Yes, I am very very greedy.
-- Open project: Wikidata integration
local infobox = require('Module:Infobox').infobox
local infoimg = requite('Module:InfoboxImage').main
local frame = nil
-- deps/subpages
-- Open project: Convert to table lookup (for plain switch tmpls) and go over 32K
-- 这谁有心情让代码更长的话改成查表吧……
local function title_return(arg1)
return frame:expandTemplate{title = '藝人/title_return', args = {arg1}}
end
local function type_return(arg1)
return frame:expandTemplate{title = '藝人/type_return', args = {arg1}}
end
local function hCard_class(arg1)
return frame:expandTemplate{title = '藝人/hCard_class', args = {arg1}}
end
local function color_selector(arg1)
return frame:expandTemplate{title = '藝人/color_selector', args = {arg1}}
end
local function lang_selector(arg1)
return frame:expandTemplate{title = '藝人/lang', args = {arg1}}
end
local function tracking(arg1)
return frame:expandTemplate{title = '藝人/tracking', args = {arg1}}
end
-- end deps
-- TODO: PoC, not filled up yet
local arg_aliases = {
['honorific_prefix'] = {'honorific prefix', '前缀尊称', '前綴尊稱'},
['name'] = {'名字', '姓名'},
['honorific_suffix'] = {'honorific suffix', '后缀尊称', '後綴尊稱'},
['type'] = {'类型', '類型', 'Background'},
['embed'] = {'嵌入'},
['image'] = {'imagename', 'image_name', 'Img', '圖片', '图片', '圖像', '图像'},
['landscape'] = {'Landscape', 'landscape', '補正', '补正'},
['imagesize'] = {'image_size', 'Img_size', '圖片尺寸', '图片尺寸', '圖像大小', '图像大小'},
['Img_alt'] = {'alt', '圖片替代', '图片替代', '圖像替代', '图像替代'},
['caption'] = {'imagecaption', 'image_caption', 'Img_capt', '圖片簡介', '图片简介', '圖像說明', '图像说明'},
['realname'] = {'real_name', 'Real_name', 'full name', '本名', '原名'},
}
local function main(args, frame)
-- Fallback magic
local oldArgsMeta = getmetatable(args) or {}
local newArgsMeta = {}
for k, v in ipairs(oldArgsMeta) do
newArgsMeta[k] = v
end
newArgsMeta.__index = function (t, k)
if oldArgsMeta.__index ~= nil then
local val = oldArgsMeta.__index(t, k)
if val ~= nil then
return val
end
end
for _, v in ipairs(arg_aliases[k] or {}) do
if t[v] ~= nil and t[v] ~= '' then
return t[v]
end
end
return nil
end
setmetatable(args, newArgsMeta)
-- Prepare to call infobox
local ibargs = {}
ibargs['child'] = args['embed']:lower()
ibargs['decat'] = 'yes'
ibargs['bodyclass'] = 'vcard'
ibargs['bodystyle'] = 'width:275px; font-size: 95%;'
ibargs['title'] = title_return(args['type'] or
(yes(ibargs['child']) and '演艺生涯' or 'none'))
-- Note: although '' is not falsy, getArgs cleans that out to match mw behavior.
ibargs['above'] = table.concat(table_filter({
(args['honorific_prefix'] and
'<span class="honorific-prefix" style="font-size: small">' .. args['honorific_prefix'] .. '</span>'),
'<span class="' .. hcard_class(args['type'] or '艺人') .. '">' .. (args['name'] or mw.title.getCurrentTitle().baseText) .. '</span>',
(args['honorific_suffix'] and
'<span class="honorific-suffix" style="font-size: small">' .. args['honorific_suffix'] .. '</span>'),
}, (function(v,k,t) return v end)), '<br />')
ibargs['abovestyle'] = 'text-align: center; font-size: 120%; background:' .. color_selector(args['type'] or '艺人')
ibargs['headerstyle'] = ((not yes(ibargs['child'])) and color_selector(args['type'] or '艺人') or '')
ibargs['labelstyle'] = 'white-space: nowrap'
ibargs['image'] = infoimg {
["image"] = args["image"],
["size"] = (yes(args['landscape']) and ((args['imagesize'] and min(300,tonumber(imagesize)) or 300) .. 'x200px') or (args['imagesize'] or '')),
["sizedefault"] = "frameless",
["upright"] = "1",
["alt"] = args['Img_alt'],
["suppressplaceholder"] = yes
}
ibargs["caption"] = args["caption"]
ibargs["class1"] = "title role"
ibargs["header1"] = "<includeonly>" .. (not yes(args['embed']) and (type_return(args['type'] or '艺人或艺术家') or ''))
ibargs["class2"] = "additional-name"
ibargs["label2"] = "本名"
ibargs["data2"] = args['realname']
ibargs["label3"] = "原文名"
ibargs["data3"] = nil -- todo
-- 我想了想,没有用 infobox{ ... } 这个语法的我真仁慈啊!(大雾)
return infobox(ibargs)
end
local function table_filter(t, filterIter)
local out = {}
for k, v in ipairs(t) do
if filterIter(v, k, t) then out[k] = v end
end
return out
end
local function yes(s)
return s:lower() == "yes"
end
local function _entry (frame_)
local args = getArgs(frame_)
frame = frame_
return p[fname](args)
end
local function _luacall(args, frame_)
frame = frame_
return main(args)
end
return {
["infobox_artist"] = _entry,
["_artist_actual"] = _luacall
}