|
Данный модуль служит для облегчения обработки аргументов, передаваемых в {{code|#invoke}}. Это мета-модуль, предназначенный для использования в других модулях, а не вики-страницах напрямую. Его функционал включает:
<noinclude><!--
* Облегчение обрезки аргументов и удаления пустых аргументов.
-->{{#ifeq:{{SUBPAGENAME}}|doc||{{Documentation subpage}}}}<!--
* Аргументы, передаваемые не только текущим фреймов, но и родительским фреймом. (См. ниже)
--><languages /><!--
* Аргументы, передаваемые из другого модуля или отладочной консоли.
--></noinclude>{{#switch:<translate></translate>
* Большинство возможностей поддаются настройке.
| =
<includeonly>{{Languages|Module:Arguments/doc}}</includeonly>
<!-- Add categories where indicated at the bottom of this page and interwikis at Wikidata -->
{{Shared Template Warning|Module:Arguments|Module:Arguments}}
{{Used in system}}
{{Module rating|release}}
{{Module rating|protected}}
См. {{рувики|Module:Arguments/doc|документацию на русской Википедии}}<includeonly>{{#ifeq:{{SUBPAGENAME}}|sandbox||
<translate><!--T:1--> This module provides easy processing of arguments passed from <tvar name=1>{{Magic word|#invoke|...|ext=Scribunto|code=1|nowrap=1}}</tvar>.</translate>
[[Категория:Модули:Базовые]]
<translate><!--T:2--> It is a meta-module, meant for use by other modules, and should not be called from <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar> directly.</translate>
}}</includeonly>
<translate><!--T:3--> Its features include:</translate>
* <translate><!--T:4--> Easy trimming of arguments and removal of blank arguments.</translate>
* <translate><!--T:5--> Arguments can be passed by both the current frame and by the parent frame at the same time.</translate> <translate><!--T:6--> (More details below.)</translate>
* <translate><!--T:7--> Arguments can be passed in directly from another Lua module or from the debug console.</translate>
* <translate><!--T:8--> Arguments are fetched as needed, which can help avoid (some) problems with <tvar name=1>{{xtag|ref}}</tvar> tags.</translate>
* <translate><!--T:9--> Most features can be customized.</translate>
<translate>
== Basic use == <!--T:10-->
</translate>
<translate><!--T:11--> First, you need to load the module.</translate>
<translate><!--T:12--> It contains one function, named <tvar name=1><code>getArgs</code></tvar>.</translate>
<syntaxhighlight lang="lua">
local getArgs = require('Module:Arguments').getArgs
</syntaxhighlight>
<translate><!--T:13--> In the most basic scenario, you can use <tvar name=1><code>getArgs</code></tvar> inside your main function.</translate>
<translate><!--T:14--> The variable <tvar name=1><code>args</code></tvar> is a table containing the arguments from <tvar name=2>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>.</translate>
<translate><!--T:15--> (See below for details.)</translate>
<syntaxhighlight lang="lua">
local getArgs = require('Module:Arguments').getArgs
local p = {}
function p.main(frame)
local args = getArgs(frame)
-- <translate nowrap><!--T:16--> Main module code goes here.</translate>
end
return p
</syntaxhighlight>
<translate><!--T:17--> However, the recommended practice is to use a function just for processing arguments from <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>.</translate>
<translate><!--T:18--> This means that if someone calls your module from another Lua module you don't have to have a frame object available, which improves performance.</translate>
<syntaxhighlight lang="lua">
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)
-- <translate nowrap><!--T:19--> Main module code goes here.</translate>
end
return p
</syntaxhighlight>
<translate>
<!--T:20-->
If you want multiple functions to use the arguments, and you also want them to be accessible from <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>, you can use a wrapper function.
</translate>
<syntaxhighlight lang="lua">
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)
-- <translate nowrap><!--T:21--> Code for the first function goes here.</translate>
end
p.func2 = makeInvokeFunc('_func2')
function p._func2(args)
-- <translate nowrap><!--T:22--> Code for the second function goes here.</translate>
end
return p
</syntaxhighlight>
<translate>
=== Options === <!--T:23-->
</translate>
<translate><!--T:24--> The following options are available.</translate>
<translate><!--T:25--> They are explained in the sections below.</translate>
<syntaxhighlight lang="lua">
local args = getArgs(frame, {
trim = false,
removeBlanks = false,
valueFunc = function (key, value)
-- <translate nowrap><!--T:26--> Code for processing one argument</translate>
end,
frameOnly = true,
parentOnly = true,
parentFirst = true,
wrappers = {
'Template:A wrapper template',
'Template:Another wrapper template'
},
readOnly = true,
noOverwrite = true
})
</syntaxhighlight>
<translate>
=== Trimming and removing blanks === <!--T:27-->
</translate>
<translate><!--T:28--> Blank arguments often trip up coders new to converting MediaWiki templates to Lua.</translate>
<translate><!--T:29--> In template syntax, blank strings and strings consisting only of whitespace are considered <tvar name=1><code>false</code></tvar>.</translate>
<translate><!--T:30--> However, in Lua, blank strings and strings consisting of whitespace are considered <tvar name=1><code>true</code></tvar>.</translate>
<translate><!--T:31--> This means that if you don't pay attention to such arguments when you write your Lua modules, you might treat something as <tvar name=1><code>true</code></tvar> that should actually be treated as <tvar name=2><code>false</code></tvar>.</translate>
<translate><!--T:32--> To avoid this, by default this module removes all blank arguments.</translate>
<translate><!--T:33--> Similarly, whitespace can cause problems when dealing with positional arguments.</translate>
<translate><!--T:34--> Although whitespace is trimmed for named arguments coming from <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>, it is preserved for positional arguments.</translate>
<translate><!--T:35--> Most of the time this additional whitespace is not desired, so this module trims it off by default.</translate>
<translate><!--T:36--> However, sometimes you want to use blank arguments as input, and sometimes you want to keep additional whitespace.</translate>
<translate><!--T:37--> This can be necessary to convert some templates exactly as they were written.</translate>
<translate><!--T:38--> If you want to do this, you can set the <tvar name=1><code>trim</code></tvar> and <tvar name=2><code>removeBlanks</code></tvar> arguments to <tvar name=3><code>false</code></tvar>.</translate>
<syntaxhighlight lang="lua">
local args = getArgs(frame, {
trim = false,
removeBlanks = false
})
</syntaxhighlight>
<translate>
=== Custom formatting of arguments === <!--T:39-->
</translate>
<translate><!--T:40--> Sometimes you want to remove some blank arguments but not others, or perhaps you might want to put all of the positional arguments in lower case.</translate>
<translate><!--T:41--> To do things like this you can use the <tvar name=1><code>valueFunc</code></tvar> option.</translate>
<translate><!--T:42--> The input to this option must be a function that takes two parameters, <tvar name=1><code>key</code></tvar> and <tvar name=2><code>value</code></tvar>, and returns a single value.</translate>
<translate><!--T:43--> This value is what you will get when you access the field <tvar name=1><code>key</code></tvar> in the <tvar name=2><code>args</code></tvar> table.</translate>
'''<translate><!--T:44--> Example 1:</translate>'''
<translate><!--T:45--> This function preserves whitespace for the first positional argument, but trims all other arguments and removes all other blank arguments.</translate>
<syntaxhighlight lang="lua">
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
})
</syntaxhighlight>
'''<translate><!--T:46--> Example 2:</translate>'''
<translate><!--T:47--> This function removes blank arguments and converts all arguments to lower case, but doesn't trim whitespace from positional parameters.</translate>
<syntaxhighlight lang="lua">
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
})
</syntaxhighlight>
{{Note|text=
<translate><!--T:48--> The above functions will fail if passed input that is not of type <tvar name=1><code>string</code></tvar> or <tvar name=2><code>nil</code></tvar>.</translate>
<translate><!--T:49--> This might be the case if you use the <tvar name=1><code>getArgs</code></tvar> function in the main function of your module, and that function is called by another Lua module.</translate>
<translate><!--T:50--> In this case, you will need to check the type of your input.</translate>
<translate><!--T:51--> This is not a problem if you are using a function specially for arguments from <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar> (i.e. you have <tvar name=2><code>p.main</code></tvar> and <tvar name=3><code>p._main</code></tvar> functions, or something similar).</translate>
}}
{{Collapse top|1=<translate><!--T:52--> Examples 1 and 2 with type checking</translate>}}
<translate>
<!--T:53-->
Example 1:
</translate>
<syntaxhighlight lang="lua">
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
})
</syntaxhighlight>
<translate>
<!--T:54-->
Example 2:
</translate>
<syntaxhighlight lang="lua">
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
})
</syntaxhighlight>
{{Collapse bottom}}
<translate>
<!--T:55-->
Also, please note that the <tvar name=1><code>valueFunc</code></tvar> function is called more or less every time an argument is requested from the <tvar name=2><code>args</code></tvar> table, so if you care about performance you should make sure you aren't doing anything inefficient with your code.
=== Frames and parent frames === <!--T:56-->
</translate>
<translate><!--T:57--> Arguments in the <tvar name=1><code>args</code></tvar> table can be passed from the current frame or from its parent frame at the same time.</translate>
<translate><!--T:58--> To understand what this means, it is easiest to give an example.</translate>
<translate><!--T:59--> Let's say that we have a module called <tvar name=1><code>Module:ExampleArgs</code></tvar>.</translate>
<translate><!--T:60--> This module prints the first two positional arguments that it is passed.</translate>
{{Collapse top|1=<translate><!--T:61--> <tvar name=1>Module:ExampleArgs</tvar> code</translate>}}
<syntaxhighlight lang="lua">
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
</syntaxhighlight>
{{Collapse bottom}}
<translate><!--T:62--> <tvar name=1><code>Module:ExampleArgs</code></tvar> is then called by <tvar name=2><code>Template:ExampleArgs</code></tvar>, which contains the code <tvar name=3><code><nowiki>{{#invoke:ExampleArgs|main|firstInvokeArg}}</nowiki></code></tvar>.</translate>
<translate><!--T:63--> This produces the result <tvar name=1>"firstInvokeArg"</tvar>.</translate>
<translate>
<!--T:64-->
Now if we were to call <tvar name=1><code>Template:ExampleArgs</code></tvar>, the following would happen:
</translate>
{{(!}} class="wikitable" style="width: 50em; max-width: 100%;"
{{!}}-
! style="width: 60%;" {{!}} <translate><!--T:65--> Code</translate>
! style="width: 40%;" {{!}} <translate><!--T:66--> Result</translate>
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs}}</nowiki></code>
{{!}} firstInvokeArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg}}</nowiki></code>
{{!}} firstInvokeArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg|secondTemplateArg}}</nowiki></code>
{{!}} firstInvokeArg secondTemplateArg
{{!)}}
<translate><!--T:67--> There are three options you can set to change this behaviour: <tvar name=1><code>frameOnly</code></tvar>, <tvar name=2><code>parentOnly</code></tvar> and <tvar name=3><code>parentFirst</code></tvar>.</translate>
<translate><!--T:68--> If you set <tvar name=1><code>frameOnly</code></tvar> then only arguments passed from the current frame will be accepted; if you set <tvar name=2><code>parentOnly</code></tvar> then only arguments passed from the parent frame will be accepted; and if you set <tvar name=3><code>parentFirst</code></tvar> then arguments will be passed from both the current and parent frames, but the parent frame will have priority over the current frame.</translate>
<translate><!--T:69--> Here are the results in terms of <tvar name=1><code>Template:ExampleArgs</code></tvar>:</translate>
<dl>
<dt><code>frameOnly</code></dt>
<dd>
{{(!}} class="wikitable" style="width: 50em; max-width: 100%;"
{{!}}-
! style="width: 60%;" {{!}} <translate><!--T:70--> Code</translate>
! style="width: 40%;" {{!}} <translate><!--T:71--> Result</translate>
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs}}</nowiki></code>
{{!}} firstInvokeArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg}}</nowiki></code>
{{!}} firstInvokeArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg|secondTemplateArg}}</nowiki></code>
{{!}} firstInvokeArg
{{!)}}
</dd>
<dt><code>parentOnly</code></dt>
<dd>
{{(!}} class="wikitable" style="width: 50em; max-width: 100%;"
{{!}}-
! style="width: 60%;" {{!}} <translate><!--T:72--> Code</translate>
! style="width: 40%;" {{!}} <translate><!--T:73--> Result</translate>
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs}}</nowiki></code>
{{!}}
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg}}</nowiki></code>
{{!}} firstTemplateArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg|secondTemplateArg}}</nowiki></code>
{{!}} firstTemplateArg secondTemplateArg
{{!)}}
</dd>
<dt><code>parentFirst</code></dt>
<dd>
{{(!}} class="wikitable" style="width: 50em; max-width: 100%;"
{{!}}-
! style="width: 60%;" {{!}} <translate><!--T:74--> Code</translate>
! style="width: 40%;" {{!}} <translate><!--T:75--> Result</translate>
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs}}</nowiki></code>
{{!}} firstInvokeArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg}}</nowiki></code>
{{!}} firstTemplateArg
{{!}}-
{{!}} <code><nowiki>{{ExampleArgs|firstTemplateArg|secondTemplateArg}}</nowiki></code>
{{!}} firstTemplateArg secondTemplateArg
{{!)}}
</dd>
</dl>
{{Note|text=
{{Ordered list
|1=
<translate><!--T:76--> If you set both the <tvar name=1><code>frameOnly</code></tvar> and <tvar name=2><code>parentOnly</code></tvar> options, the module won't fetch any arguments at all from <tvar name=3>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>.</translate>
<translate><!--T:77--> This is probably not what you want.</translate>
|2=
<translate><!--T:78--> In some situations a parent frame may not be available, e.g. if <tvar name=1><code>getArgs</code></tvar> is passed the parent frame rather than the current frame.</translate>
<translate><!--T:79--> In this case, only the frame arguments will be used (unless <tvar name=1><code>parentOnly</code></tvar> is set, in which case no arguments will be used) and the <tvar name=2><code>parentFirst</code></tvar> and <tvar name=3><code>frameOnly</code></tvar> options will have no effect.</translate>
}}
}}
<translate>
=== Wrappers === <!--T:80-->
</translate>
<translate><!--T:81--> The <tvar name=1><code>wrappers</code></tvar> option is used to specify a limited number of templates as ''wrapper templates'', that is, templates whose only purpose is to call a module.</translate>
<translate><!--T:82--> If the module detects that it is being called from a wrapper template, it will only check for arguments in the parent frame; otherwise it will only check for arguments in the frame passed to <tvar name=1><code>getArgs</code></tvar>.</translate>
<translate><!--T:83--> This allows modules to be called by either <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar> or through a wrapper template without the loss of performance associated with having to check both the frame and the parent frame for each argument lookup.</translate>
<translate><!--T:84--> For example, the only content of <tvar name=1>{{tlx|Navbox}}</tvar> (excluding content in <tvar name=2>{{tag|noinclude}}</tvar> tags) is <tvar name=3><code><nowiki>{{#invoke:Navbox|navbox}}</nowiki></code></tvar>.</translate>
<translate><!--T:85--> There is no point in checking the arguments passed directly to the <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar> statement for this template, as no arguments will ever be specified there.</translate>
<translate><!--T:86--> We can avoid checking arguments passed to <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar> by using the <tvar name=2><code>parentOnly</code></tvar> option, but if we do this then <tvar name=1>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar> will not work from other pages either.</translate>
<translate><!--T:87--> If this were the case, then {{<tvar name=1>tmpl|0={{para|text|$1}}</tvar>|Some text}} in the code {{<tvar name=2>tmpl|0={{tlc|<nowiki>#invoke:Navbox</nowiki>|navbox|3=text=$1}}</tvar>|Some text}} would be ignored completely, no matter what page it was used from.</translate>
<translate><!--T:88--> By using the <tvar name=1><code>wrappers</code></tvar> option to specify <tvar name=2>[[Template:Navbox]]</tvar> as a wrapper, we can make {{<tvar name=3>tmpl|0={{tlc|<nowiki>#invoke:Navbox</nowiki>|main|3=text=$1}}</tvar>|Some text}} work from most pages, while still not requiring that the module check for arguments on the <tvar name=2>[[Template:Navbox]]</tvar> page itself.</translate>
<translate>
<!--T:89-->
Wrappers can be specified either as a string, or as an array of strings.
</translate>
<syntaxhighlight lang="lua">
local args = getArgs(frame, {
wrappers = 'Template:Wrapper template'
})
</syntaxhighlight>
<syntaxhighlight lang="lua">
local args = getArgs(frame, {
wrappers = {
'Template:Wrapper 1',
'Template:Wrapper 2',
-- <translate nowrap><!--T:90--> Any number of wrapper templates can be added here.</translate>
}
})
</syntaxhighlight>
{{Note|text=
{{Ordered list
|1=
<translate><!--T:91--> The module will automatically detect if it is being called from a wrapper template's <tvar name=1><code>/sandbox</code></tvar> subpage, so there is no need to specify sandbox pages explicitly.</translate>
|2=
<translate><!--T:92--> The <tvar name=1><code>wrappers</code></tvar> option effectively changes the default of the <tvar name=2><code>frameOnly</code></tvar> and <tvar name=3><code>parentOnly</code></tvar> options.</translate>
<translate><!--T:93--> If, for example, <tvar name=1><code>parentOnly</code></tvar> were explicitly set to <tvar name=2><code>false</code></tvar> with <tvar name=3><code>wrappers</code></tvar> set, calls via wrapper templates would result in both frame and parent arguments being loaded, though calls not via wrapper templates would result in only frame arguments being loaded.</translate>
|3=
<translate><!--T:94--> If the <tvar name=1><code>wrappers</code></tvar> option is set and no parent frame is available, the module will always get the arguments from the frame passed to <tvar name=2><code>getArgs</code></tvar>.</translate>
}}
}}
<translate nowrap>
=== Writing to the <tvar name=1><code>args</code></tvar> table === <!--T:95-->
</translate>
<translate><!--T:96--> Sometimes it can be useful to write new values to the <tvar name=1><code>args</code></tvar> table.</translate>
<translate><!--T:97--> This is possible with the default settings of this module.</translate>
<translate><!--T:98--> (However, bear in mind that it is usually better coding style to create a new table with your new values and copy arguments from the <tvar name=1><code>args</code></tvar> table as needed.)</translate>
<syntaxhighlight lang="lua">
args.foo = '<translate nowrap><!--T:99--> some value</translate>'
</syntaxhighlight>
<translate><!--T:100--> It is possible to alter this behaviour with the <tvar name=1><code>readOnly</code></tvar> and <tvar name=2><code>noOverwrite</code></tvar> options.</translate>
<translate><!--T:101--> If <tvar name=1><code>readOnly</code></tvar> is set then it is not possible to write any values to the <tvar name=2><code>args</code></tvar> table at all.</translate>
<translate><!--T:102--> If <tvar name=1><code>noOverwrite</code></tvar> is set, then it is possible to add new values to the table, but it is not possible to add a value if it would overwrite any arguments that are passed from <tvar name=2>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>.</translate>
<translate>
=== Ref tags === <!--T:103-->
</translate>
<translate><!--T:104--> This module uses [[<tvar name=1>mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#Metatables</tvar>|metatables]] to fetch arguments from <tvar name=2>{{tlc|<nowiki>#invoke:...</nowiki>}}</tvar>.</translate>
<translate><!--T:105--> This allows access to both the frame arguments and the parent frame arguments without using the <tvar name=1><code>pairs()</code></tvar> function.</translate>
<translate><!--T:106--> This can help if your module might be passed <tvar name=1>{{xtag|ref}}</tvar> tags as input.</translate>
<translate><!--T:107--> As soon as <tvar name=1>{{xtag|ref}}</tvar> tags are accessed from Lua, they are processed by the MediaWiki software and the reference will appear in the reference list at the bottom of the article.</translate>
<translate><!--T:108--> If your module proceeds to omit the reference tag from the output, you will end up with a phantom reference - a reference that appears in the reference list, but no number that links to it.</translate>
<translate><!--T:109--> This has been a problem with modules that use <tvar name=1><code>pairs()</code></tvar> to detect whether to use the arguments from the frame or the parent frame, as those modules automatically process every available argument.</translate>
<translate><!--T:110--> This module solves this problem by allowing access to both frame and parent frame arguments, while still only fetching those arguments when it is necessary.</translate>
<translate><!--T:111--> The problem will still occur if you use <tvar name=1><code>pairs(args)</code></tvar> elsewhere in your module, however.</translate>
<translate>
=== Known limitations === <!--T:112-->
</translate>
<translate><!--T:113--> The use of metatables also has its downsides.</translate>
<translate><!--T:114--> Most of the normal Lua table tools won't work properly on the <tvar name=4><code>args</code></tvar> table, including the <tvar name=1><code>#</code></tvar> operator, the <tvar name=2><code>next()</code></tvar> function, and the functions in the <tvar name=3><code>table</code></tvar> library.</translate>
<translate><!--T:115--> If using these is important for your module, you should use your own argument processing function instead of this module.</translate>
<translate>
== Tests == <!--T:116-->
</translate>
{{ModuleQuality}}
<includeonly>{{Sandbox other||
<!-- Categories below this line; interwikis at Wikidata -->
[[Category:Lua metamodules{{#translation:}}]]
}}</includeonly><noinclude>
[[Category:Module documentation pages{{#translation:}}]]
</noinclude>
| #default=
{{#invoke:Template translation|renderTranslatedTemplate|template=Module:Arguments/doc|noshift=1|uselang={{int:lang}}}}
}}
|