Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Wikipedia:Guide to Scribbling

From Wikipedia, the free encyclopedia
Wikipedia information page
This is aninformation page.
It is neither anencyclopedia article nor one ofWikipedia's policies or guidelines; rather, its purpose is to explain certain aspects of Wikipedia's norms, customs, technicalities, or practices. It may reflect differing levels ofconsensus andvetting.
This page in a nutshell: Scribbling involves converting templates to use Lua scripts for improved performance and maintainability by having the template invoke Lua-based modules. This enables efficient handling of logic and reduces the reliance on complexparser functions. For example,{{#invoke:Name1|Name2}} invokes the Lua script atModule:Name1. To get started, refer toModule:Example. Try the module by usingTemplate:Basic scribbling example inyour sandbox.
"Shh! I'm reading about how to Scribble templates."

This is a guide toScribbling, also known asLuafication. Scribbling is an informal term used to describe the process of creating a newtemplate or converting an existing one so that it invokes amodule containingfunctions written inLua script. TheScribunto[a] extension enables the embedding of scripting languages inMediaWiki. Currently, Lua is the only supported scripting language. This guide provides an overview of Scribbling and points to additional resources for further learning.

Scribbled templates consist of two components: The template itself, and one or more back-end modules, stored in theModule: namespace. These modules contain Lua programs that are executed on thewiki servers to generate thewikitext that the template expands to.Templates invoke a function within a module using the{{#invoke:}}parser function.

The main purpose and primary advantage of Scribbling is improved template processing performance, as Lua scripts are significantly more efficient than traditional template parser functions. Another benefit is simplified code. By using Lua, Scribbling eliminates the need forcomplex parser function programming, such as{{#if}},{{#ifeq}},{{#switch}} and{{#expr}}, which were originally designed as extensions to a template system rather than a true programming language.[b] By handling complex logic within the module, Scribbling reduces clutter in the template itself, making it easier to maintain and update. Additionally, Scribbling addresses the issue ofexpansion depth limits by eliminating the need for templates totransclude other templates.[c]

Lua

[edit]
Further information:Lua (programming language),Help:Lua for beginners, andWikipedia:Guide to Scribbling/Programmers' Quick start Guide to Lua

The language in which modules are written is Lua. Unlike the template parser function system, Lua was actually designed not only to be a proper programming language, but also to be a programming language that is suitable for what is known asembedded scripting. Modules in MediaWiki are an example of embedded scripts. There are several embedded scripting languages that could have been used, includingREXX andtcl; and indeed the original aim of Scribunto was to make available a choice of such languages. At the moment, however, only Lua is available.

The official reference manual for Lua isIerusalimschy, de Figueiredo & Celes 2006. It's a reference, not a tutorial. Consult it if you want to know the syntax or semantics for something. For a tutorial, see eitherIerusalimschy 2006 (Ierusalimschy 2003 is also available, although it is of course out of date.) orJung & Brown 2007. The downsides to these books are that quite a lot of the things that they tell you about have no bearing upon using Lua in MediaWiki modules. You don't need to know how to install Lua and how to integrate its interpreter into a program or run it standalone. The MediaWiki developers have done all of that. Similarly, a lot of the Lua library functions are, for security, not available in modules. (For example, it's not possible to do file I/O or to make operating system calls in MediaWiki modules.) So, much of what these books explain about Lua standard library functions and variables that come with the language is either irrelevant or untrue here.

The original API specification — the Lua standard library functions and variables that are supposed to be available in modules — is given atMW:Extension:Scribunto/API specification. However, even that is untrue. What you'llactually have available is documented inMW:Extension:Scribunto/Lua reference manual, which is a cut down version of the 1st Edition Lua manual that has been edited down and modified by Tim Starling to bring it more into line with the reality of Scribbling. Again, though, this is a reference manual, not a tutorial.

The things in Lua that you will mostly be concerned with, writing Scribbled templates, aretables,stringsnumbers,booleans,nil,if...then...else...end,while...do...end,for...in...do...end (generatedfor),for...do...end (numericalfor),repeat...until,function...end,local,return,break, expressions and the various operators (including#,.., the arithmetic operators+,-,*,/,^, and%), and thestring,math, andmw global tables (i.e. libraries).

Template structure

[edit]

This is simple. Your template comprises one expansion of{{#invoke:}} in the usual case. Here is{{Harvard citation}}, for example:

<includeonly>{{#invoke:Footnotes|harvard_citation|bracket_left= (|bracket_right= )}}</includeonly><noinclude>{{documentation}}<!-- Add categories to the /doc subpage, interwikis to Wikidata, not here --></noinclude>

If you find yourself wanting to use other templates within your template, or to use template parser functions, or indeed anything at all other than{{#invoke:}} and possibly somevariables as its arguments,then you are using the wrong approach.

Module basics

[edit]

Overall structure

[edit]

Let's consider a hypothetical module,Module:Population. It can be structured in one of two ways:

A named local table

[edit]
localp={}functionp.India(frame)return"1,21,01,93,422 people at (nominally) 2011-03-01 00:00:00 +0530"endreturnp

An unnamed table generated on the fly

[edit]
return{India=function(frame)return"1,21,01,93,422 people at (nominally) 2011-03-01 00:00:00 +0530"end}

Execution

[edit]

The execution of a module by{{#invoke:}} is actually twofold:

  1. The module is loaded and the entire script is run. This loads up any additional modules that the module needs (using therequire() function), builds the (invocable) functions that the module will provide to templates, and returns a table of them.
  2. The function named in{{#invoke:}} is picked out of the table built in phase 1 and called, with the arguments supplied to the templateand the arguments supplied to{{#invoke:}} (more on whichlater).

The first Lua script does phase 1 fairly explicitly. It creates alocal variable namedp on line 1, initialized to a table; builds and adds a function to it (lines 3–5), by giving the function the nameIndia in the table named byp (functionp.India being the same as sayingp["India"]=function[d]); and then returns (on line 7) the table as the last line of the script. To expand such a script with more (invocable) functions, one adds them between thelocal statement at the top and thereturn statement at the bottom. (Non-invocablelocal functions can be addedbefore thelocal statement.) The local variable doesn't have to be namedp. It could be named any valid Lua variable name that you like.p is simply conventional for this purpose, and is also the name that you can use to test the script in the debug console of the Module editor.

The second Lua script does the same thing, but more "idiomatically". Instead of creating a named variable as a table, it creates an anonymous table on the fly, in the middle of thereturn statement, which is the only (executed during the first phase) statement in the script. TheIndia=function(frame)...end on lines 2–4 creates an (also anonymous) function and inserts it into the table under the nameIndia. To expand such a script with more (invocable) functions, one adds them as further fields in the table. (Non-invocablelocal functions can, again, be addedbefore thereturn statement.)

In both cases, the template code that one writes is{{#invoke:Population|India}} toinvoke the function namedIndia from the moduleModule:Population. Also note thatfunctionbuilds a function, as an object, to be called. It doesn'tdeclare it, as you might be used to from other programming languages, and the function isn't executed until itis called.

One can do more complex things than this, of course. For example: One can declare other local variables in addition top, to hold tables of data (such as lists of Language or country names), that the module uses. But this is thebasic structure of a module. You make a table full of stuff, and return it.

Receiving template arguments

[edit]

An ordinary function in Lua can take an (effectively) arbitrary number of arguments. Witness this function fromModule:Wikitext that can be called with anywhere between zero and three arguments:

functionz.oxfordlist(args,separator,ampersand)

Functions called by{{#invoke:}} are special. They expect to be passed exactly one argument, a table that is called aframe (and so is conventionally given the parameter nameframe in the parameter list of the function). It's called aframe because, unfortunately, the developers chose to name it for their convenience. It's named after an internal structure within the code of MediaWiki itself, which itsort of represents.[e]

This frame has a (sub‑)table within it, namedargs. It also has a means for accessing itsparent frame (again, named after a thing in MediaWiki). The parent framealso has a (sub‑)table within it, also namedargs.

  • The arguments in the (child, one supposes) frame — i.e. the value of theframe parameter to the function — are the arguments passed to{{#invoke:}}within the wikitext of your template. So, for example, if you were to write{{#invoke:Population|India|a|b|class="popdata"}} in your template then the arguments sub‑table of the child frame would be (as written in Lua form){"a","b",class="popdata"}.
  • The arguments in the parent frame are the argumentspassed to your template when it was transcluded. So, for example, were the user of your template to write{{Population of India|c|d|language=Hindi}} then the arguments sub‑table of the parent frame would be (as written in Lua form){"c","d",language="Hindi"}.

A handy programmers' idiom that you can use, to make this all a bit easier, is to have local variables named (say)config andargs in your function, that point to these two argument tables. See this, fromModule:WikidataCheck:

functionp.wikidatacheck(frame)localpframe=frame:getParent()localconfig=frame.args-- the arguments passed BY the template, in the wikitext of the template itselflocalargs=pframe.args-- the arguments passed TO the template, in the wikitext that transcludes the template

Everything inconfig is thus an argument thatyou have specified, in your template, that you can reference with code such asconfig[1] andconfig["class"]. These will be things that tell your module function its "configuration" (e.g. a CSS class name that can vary according to what template is used).

Everything inargs is thus an argument thatthe user of the template has specified, where it was transcluded, that you can reference with code such asargs[1] andargs["language"]. These will be the normal template arguments, as documented on your template's/doc page.

See{{other places}} and{{other ships}} for two templates that both do{{#invoke:Other uses|otherX|x}} but do so with different arguments in place of thex, thereby obtaining different results from one single common Lua function.

For both sets of arguments, the name and value of the argument are exactly as in the wikitext, except that leading and trailing whitespace in named parameters is discounted. This has an effect on your code if you decide to support or employ transclusion/invocation argument names that aren't valid Lua variable names. You cannot use the "dot" form of table lookup in such cases. For instance:args.author-first is, as you can see from the syntax colourization here, not a reference to an|author-first= argument, but a reference to an|author= argument and afirst variable with the subtraction operator in the middle. To access such an argument, use the "square bracket" form of table lookup:args["author-first"].

Named arguments are indexed in theargs table by their name strings, of course. Positional arguments (whether as the result of an explicit1= or otherwise) are indexed in theargs tables by number, not by string.args[1] is not the same asargs["1"], and the latter is effectively unsettable from wikitext.

Finally, note that Lua modules can differentiate between arguments that have been used in the wikitext and simply set to an empty string, and arguments that aren't in the wikitext at all. The latter don't exist in theargs table, and any attempt to index them will evaluate tonil. Whereas the formerdo exist in the table and evaluate to an empty string,"".

Errors

[edit]

Let's get one thing out of the way right at the start:Script error is a hyperlink. You can put the mouse pointer on it and click.

We've become so conditioned by our (non-Scribbled) templates putting out error messages in red that we think that the Scribunto "Script error" error message is nothing but more of the same. It isn't. If you haveJavaScript enabled in your WWW browser, it will pop up a window giving the details of the error, a call backtrace, and even hyperlinks that will take you to the location of the code where the error happened in the relevant module.

You can cause an error to happen by calling theerror() function.

Tips and tricks

[edit]

Arguments tables are "special".

[edit]

For reasons that are out of the scope of this Guide,[f] theargs sub-table of a frame is not quite like an ordinary table. It starts out empty, and it is populated with arguments as and when you execute code that looks for them.[g] (It's possible to make tables that work like this in a Lua program, using things calledmetatables. That, too, is outwith the scope of this Guide.)

An unfortunate side-effect of this is that some of the normal Lua table operators don't work on anargs table. The length operator,#, will not work, and neither will the functions in Lua'stable library. These only work with standard tables, and fail when presented with the specialargs table. However, thepairs() andipairs() functions will both work, as code to make their use possible has been added by the developers.

Copy table contents into local variables.

[edit]

A name in Lua is either an access of a local variable or a table lookup.[3]math.floor is a table lookup (of the string"floor") in the (global)math table, for example. Table lookups are slower, at runtime, than local variable lookups. Table lookups in tables such as theargs table withits "specialness" are alot slower.

A function in Lua can have up to 250 local variables.[4] So make liberal use of them:

  • If you callmath.floor many times, copy it into a local variable and use that instead:[4]
    localfloor=math.floorlocala=floor((14-date.mon)/12)localy=date.year+4800-alocalm=date.mon+12*a-3returndate.day+floor((153*m+2)/5)+365*y+floor(y/4)-floor(y/100)+floor(y/400)-2432046
  • Don't useargs.something over and over. Copy it into a local variable and use that:
    localTab=args.tab
    (Even theargs variable itself is a way to avoid looking up"args" in theframe table over and over.)

When copying arguments into local variables there are two useful things that you can do along the way:

  • Thealternative names for the same argument trick. If a template argument can go by different names — such as uppercase and lowercase forms, or different English spellings — then you can use Lua'sor operator to pick the highest priority name that is actually supplied:
    localTitle=args.titleorargs.encyclopaediaorargs.encyclopediaorargs.dictionarylocalISBN=args.isbn13orargs.isbnorargs.ISBN

This works for two reasons:

    • nil is the same asfalse as far asor is concerned.
    • Lua'sor operator has what are known as "shortcut" semantics. If the left-hand operand evaluates to something that isn'tfalse ornil, it doesn't bother even working out the value of the right-hand operand. (So whilst that first example may at first glance look like it does four lookups, in the commonest case, where|title= is used with the template, it in fact only actually does one.)
  • Thedefault to empty string trick. Sometimes the fact that an omitted template argument isnil is useful. Other times, however, it isn't, and you want the behaviour of missing arguments being empty strings. A simpleor"" at the end of an expression suffices:
    localID=args.idorargs.IDorargs[1]or""

Don't expand templates, even though you can.

[edit]

If local variables are cheap and table lookups are expensive, then template expansion is way above your price bracket.

Avoidframe:preprocess() like the plague. Nested template expansion using MediaWiki's preprocessor is what we're trying to get away from, after all. Most things that you'd do with that are done more simply, more quickly, and more maintainably, with simple Lua functions.

Similarly, avoid things like usingw:Template:ISO 639 name aze (deleted August 2020) to store what is effectively an entry in a database. Reading it would be a nested parser call with concomitant database queries, all to map a string onto another string. Put a simple straightforward data table in your module, like the ones inModule:Wikt-lang.

Notes

[edit]
  1. ^The name "Scribunto" is Latin. "scribunto" is third person pluralfutureactiveimperative of "scribere" and means "they shall write". "scribble" is of course an English word derived from that Latin word, viaMediaeval Latin "scribillare".[1]
  2. ^For an idea of what "bolted-on" connotes when it comes to software design, see theFlintstones cartoons where the rack of ribs from the Drive-Thru is so heavy that it causes the Flintstones' car to fall on its side.
  3. ^It may need, until such time as the whole of the specified API for Scribunto is available to modules, to transcludemagic words. Seethe tips and tricks section. Magic words are not templates, however.
  4. ^The inventors of the language call thissyntactic sugar.[2]
  5. ^In MediaWiki proper, there are more than two frames.
  6. ^If you want to know, go and read about how MediaWiki, in part due to the burden laid upon it by the old templates-conditionally-transcluding-templates system, doeslazy evaluation of template arguments.
  7. ^Don't be surprised, therefore, if you find a call backtrace showing a call to some other module in what you thought was an ordinary template argument reference. That will be because expansion of that argument involved expanding another Scribbled template.

References

[edit]

Cross-references

[edit]
  1. ^MW 2003a, p. 1116.
  2. ^Ierusalimschy, de Figueiredo & Celes 2011, §DATA.
  3. ^Ierusalimschy, de Figueiredo & Celes 2011, §EVAL AND ENVIRONMENTS.
  4. ^abIerusalimschy 2008, p. 17.

Citations

[edit]
  • "scribble".Merriam-Webster's Collegiate Dictionary: Eleventh Edition.Merriam-Webster's Collegiate Dictionary (11th ed.). Merriam-Webster. 2003. p. 1116.ISBN 9780877798095.
  • Ierusalimschy, Roberto; de Figueiredo, Luiz Henrique; Celes, Waldemar (12 May 2011)."Passing a Language through the Eye of a Needle".ACM Queue.9 (5). Association for Computing Machinery. ACM 1542-7730/11/0500.
  • Ierusalimschy, Roberto (December 2008)."Lua Performance Tips"(PDF). In de Figueiredo, Luiz Henrique; Celes, Waldemar; Ierusalimschy, Roberto (eds.).Lua Programming Gems. Lua.org.ISBN 978-85-903798-4-3.

Further reading

[edit]

Lua

[edit]
General
technical help
Special
page
-related
Wikitext
Links anddiffs
Media files: images,
videos and sounds
Other graphics
Templates and
Lua modules
Data structure
HTML andCSS
Customisation
and tools
Automated editing
Retrieved from "https://en.wikipedia.org/w/index.php?title=Wikipedia:Guide_to_Scribbling&oldid=1312814176"
Categories:

[8]ページ先頭

©2009-2025 Movatter.jp