此頁面為 Module:Arguments 的說明文件

此模塊是調用其他模塊的模塊。

此模塊提供了對通過{{#invoke:}}(以下簡稱#invoke)傳遞參數的簡單處理。這是元模塊(meta-module),只能被其他模塊使用,而不應被#invoke直接調用。其特性如下:

  • 對參數的簡易修整,移除空白參數。
  • 參數可以在當前框架或父框架中同時傳遞。(具體見下)
  • 參數可以直接通過其他Lua模塊或調試控制台傳遞。
  • 可自定義更多特性。

基本用法

編輯

首先,您需要通過require函數加載這個模塊。這個模塊包含了一個名為getArgs的函數。

local getArgs = require('Module:Arguments').getArgs

最簡單的方法是在使用getArgs函數。變量args是包含#invoke參數的表(table)。(詳見下文。)

local getArgs = require('Module:Arguments').getArgs
local p = {}

function p.main(frame)
	local args = getArgs(frame)
	-- 主要的模块放此处。
end

return p

最佳實踐

編輯

最佳的做法是,先用專門的函數來處理來自#invoke的參數。這樣,其他Lua模塊直接調用該模塊時,就無需再需要弄一個frame對象,從而提升性能,減小開銷。

local getArgs = require('Module:Arguments').getArgs
local p = {}

function p.main(frame)
	local args = getArgs(frame) -- 从#invoke中获得的参数
	return p._main(args)
end

function p._main(args)
	-- 主要模块放此处。
end

return p

多個函數

編輯

如果你需要多個函數使用這些參數,而且你希望這些函數可用於#invoke,你可以使用包裝函數(wrapper function)。

local getArgs = require('Module:Arguments').getArgs

local p = {}

local function makeInvokeFunc(funcName)
	return function (frame)
		local args = getArgs(frame)
		return p[funcName](args)
	end
end

p.func1 = makeInvokeFunc('_func1')

function p._func1(args)
	-- 第一个函数的代码。
end

p.func2 = makeInvokeFunc('_func2')

function p._func2(args)
	-- 第二个函数的代码。
end

return p

選項

編輯

你可以使用如下面這段代碼所示的選項。這些選項會在下文中介紹。

local args = getArgs(frame, {
	trim = false,
	removeBlanks = false,
	valueFunc = function (key, value)
		-- 用于处理一个参数的函数的代码。
	end,
	frameOnly = true,
	parentOnly = true,
	parentFirst = true,
	wrappers = {
		'Template:一个包装模板',
		'Template:另一个模板'
	},
	readOnly = true,
	noOverwrite = true
})

修整參數和移除空白的參數

編輯

將模板轉換為Lua的新手易在空白參數上犯錯。在模板語法中,空白字符串和僅包含空白字符(whitespace,空格、換行等)的字符串被視為假(false)。然而,在Lua,空白字符串和只包含空白字符的字符串則會被視為真(true)。這就是說,如果你在寫Lua模塊時,不注意這些參數,你可能會把本想視為假的東西視為真。為了避免這種情況,這個模塊默認會移除所有的空白參數。

類似地,空白字符在處理位置參數(positional arguments)時會發生問題。雖然來自#invoke的具名參數(named arguments)中的多餘空白字符會被修整(trim),但是對一些位置參數仍然保留。大多數時候,多餘的空白字符是不需要的,所以這個模塊默認剔除這些空白字符。

然而,有時輸入時又需要使用這些空白字符,或者需要保留空白參數。把某些模板準確地轉化為模塊時,可能有必要這麼做。如果你需要這樣,你可以將trimremoveBlanks參數設為false

local args = getArgs(frame, {
	trim = false,
	removeBlanks = false
})

對參數進行自定義格式化

編輯

有時,你需要移除某些空白參數,但是還有些空白參數又不想移除,或者,你需要將所有位置參數轉化為小寫字母。你可以使用valueFunc選項。這個參數的值必須是一個接收兩個參數keyvalue並且只返回一個值的函數,這個值是你在args表中索引名為key的域時得到的值。

例1:這個函數不會動第一個參數的空白字符,但是其他參數的空白字符會剔除並移除其他所有空白參數。

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if key == 1 then
			return value
		elseif value then
			value = mw.text.trim(value)
			if value ~= '' then
				return value
			end
		end
		return nil
	end
})

例2:這個函數移除空白參數並將所有參數轉化為小寫字母,但是不會剔除位置參數的空白字符。

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if not value then
			return nil
		end
		value = mw.ustring.lower(value)
		if mw.ustring.find(value, '%S') then
			return value
		end
		return nil
	end
})

註:如果傳入了既不是字符串又不是空值(nil)的值,上面這個函數會失敗。當你在你的模塊的主函數使用getArgs函數,而且那個函數被另一個Lua模塊調用時,就可能出現此情況。這種情況下,你需要檢查你輸入的內容的類型(type)。如果你使用一個專門用於來自#invoke的參數的函數時,不會有這個問題,你如你有p.mainp._main函數,或者類似。

帶有數據類型檢查功能的例1和例2

例1:

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if key == 1 then
			return value
		elseif type(value) == 'string' then
			value = mw.text.trim(value)
			if value ~= '' then
				return value
			else
				return nil
			end
		else
			return value
		end
	end
})

例2:

local args = getArgs(frame, {
	valueFunc = function (key, value)
		if type(value) == 'string' then
			value = mw.ustring.lower(value)
			if mw.ustring.find(value, '%S') then
				return value
			else
				return nil
			end
		else
			return value
		end
	end
})

而且,請注意,每次從args表中請求參數時,都會調用valueFunc函數,所以請留意性能,確保不要加入低效的代碼。

框架與父框架

編輯

args表中的參數可以從當前框架或父框架同時傳遞。這句話有點難懂,可以看下面的例子。假設我們有個稱為模块:ExampleArgs的模塊,這個模塊輸出(print)前兩個傳入的位置參數。

模塊:ExampleArgs的代碼
local getArgs = require('Module:Arguments').getArgs
local p = {}

function p.main(frame)
	local args = getArgs(frame)
	return p._main(args)
end

function p._main(args)
	local first = args[1] or ''
	local second = args[2] or ''
	return first .. ' ' .. second
end

return p

然後,模块:ExampleArgs模板:ExampleArgs調用,模板:ExampleArgs內容如下:{{#invoke:ExampleArgs|main|firstInvokeArg}}。它會輸出內容firstInvokeArg。

現在,如果我們調用模板:ExampleArgs,其結果如下表所示:

代碼 結果
{{ExampleArgs}} firstInvokeArg
{{ExampleArgs|firstTemplateArg}} firstInvokeArg
{{ExampleArgs|firstTemplateArg|secondTemplateArg}} firstInvokeArg secondTemplateArg

有三個選項可以用來改變行為:frameOnlyparentOnlyparentFirst。如果設置frameOnly,那麼只有從當前框架傳入的參數可以被接受;如果設置 parentOnly,那麼只有從父框架傳入的參數會被接受;如果你設置parentFirst,那麼當前框架和父框架的參數都會接受,但是父框架優先於當前框架。以下是對於模板:ExampleArgs的結果:

設為frameOnly時
代碼 結果
{{ExampleArgs}} firstInvokeArg
{{ExampleArgs|firstTemplateArg}} firstInvokeArg
{{ExampleArgs|firstTemplateArg|secondTemplateArg}} firstInvokeArg
設為parentOnly時
代碼 結果
{{ExampleArgs}}
{{ExampleArgs|firstTemplateArg}} firstTemplateArg
{{ExampleArgs|firstTemplateArg|secondTemplateArg}} firstTemplateArg secondTemplateArg
設為parentFirst時
代碼 結果
{{ExampleArgs}} firstInvokeArg
{{ExampleArgs|firstTemplateArg}} firstTemplateArg
{{ExampleArgs|firstTemplateArg|secondTemplateArg}} firstTemplateArg secondTemplateArg

注意:

  1. 如果你同時設置了frameOnlyparentOnly兩個選項,模塊將不會從#invoke獲取任何參數。這顯然不是你需要的。
  2. 有時,父框架可能無效,比如getArgs是從父框架傳入的,而不是當前框架。這種情況下,只有框架參數會被使用(除非設置了parentOnly,那種情況下不會使用任何參數),而且parentFirstframeOnly選項都會沒有效果。

包裝

編輯

包裝(wrapper)選項用於指定一部分模板作為包裝模板(wrapper templates),也就是說,要調用模塊的模板。如果模塊檢測到是被包裝模板調用的,則只會檢查父框架中的參數;否則,只檢查傳遞到getArgs的框架的參數。這允許模塊要麼被#invoke調用,要麼通過包裝模板調用,而不會由於為每次參數尋找(argument lookup)同時檢查框架和父框架而損失性能。

比如,Template:Side box的內容(除了<noinclude>...</noinclude>標籤內的)為{{#invoke:Side box|main}}。檢查直接傳遞到模板的#invoke語句的參數是沒有道理的,因為這裡沒有指定參數。我們可以通過parentOnly選項避免檢查傳遞到#invoke的參數,但如果這樣做,#invoke也不會從其他頁面起作用。如果是這樣,代碼{{#invoke:Side box|main|text=Some text}}中的|text=Some text會直接忽略,無論是從哪個頁面使用的。使用wrappers選項以指定「Template:Side box」為包裝,我們可以使得{{#invoke:Side box|main|text=一些文本}}能夠從大多數頁面使用,而不需要檢查Template:Side box頁面自身的參數。

容器可以指定為字符串,或字符串的數組。

local args = getArgs(frame, {
	wrappers = 'Template:Wrapper template'
})


local args = getArgs(frame, {
	wrappers = {
		'Template:Wrapper 1',
		'Template:Wrapper 2',
		-- 可以在此处添加多个包装模板。
	}
})

注意:

  1. 模塊會自動檢測是否是從包裝模板的/sandbox子頁面調用的,所以不需要清楚地指定沙盒頁面。
  2. wrappers選項有效改變frameOnlyparentOnly的默認的選項。如果,比如,設置了wrappers時清楚地將parentOnly設為false,通過包裝模板調用會導致同時加載框架和父框架的參數,儘管非經由包裝模板的調用會導致只加載框架參數。
  3. 如果設置了wrappers但是沒有可用的父框架,模塊總是會從傳遞給getArgs的框架中得到參數。

寫入參數表

編輯

有時給參數表寫入新值會很有用。這可以通過此模塊的默認設置實現。(然而,記住最好的代碼風格是,將需要的參數表中的參數複製到一個新的表中。)

args.foo = '一些值'

可以帶有readOnlynoOverwrite選項修改此行為。如果設置了readOnly,則完全不可能將任何值寫到參數表中。如果設置了noOverwrite,則可以將新值添加到此表,但是如果需要重寫從#invoke傳遞的任何參數則不可能添加值。

ref標籤

編輯

模塊使用元表以從#invoke中獲取參數。這允許不使用pairs()函數就獲取框架參數和父框架參數。如果你需要將<ref>...</ref>標籤作為輸入時,這會很有用。

<ref>...</ref>標籤是從Lua中獲取的,因此會被MediaWiki軟件處理,引用會在文章底部的參考文獻列表中顯示。如果模塊繼續從輸出中省略索引標籤,則會產生一個假引用 —— 在參考文獻列表中顯示,但是沒有與之鏈接的數字。模塊如果使用pairs()來檢測是否從框架或父框架中使用參數,就會出現此問題,因為這些模塊會自動處理每一個可用變量。

此模塊允許既獲取框架又獲取父框架而僅在需要時獲取這些參數,從而解決此問題。然而,模塊其他位置使用pairs(args)時,仍會出現此問題。

已知限制

編輯

元表(metatable)的使用也有其缺點。大多數正常Lua表工具都不會對args表正常工作,包括#操作符號、next()函數和表庫(table library)中的函數。如果這對你的模塊重要,你需要使用你自己的用來處理參數的函數,而不是這個模塊。