此頁面為 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)中的函式。如果這對你的模組重要,你需要使用你自己的用來處理參數的函式,而不是這個模組。