Module:Buffer/doc: Difference between revisions

Content deleted Content added
save
save
Line 1:
{{Tmbox|image=[[File:Stop_hand_nuvola.svg|40px]]|text=Do not "beautify" the source of this metamodule. Its unconventional syntax was developed using the [[scientific method]] for performance. For example, {{code|lang=lua|1=v2~=true and v2~=false}}, though longer than {{code|lang=lua|1=type(v2)=~='boolean'|lang=lua}}, runsis about 8 times faster per op. (WhileThough the {{luaref|type}} op is generallynormally inexpensivetrivial, anythe "[[Aerodynamicway drag|drag]]"this onis thisused metamodulecould iscause multipliedany byinefficiency theto millionsbe ofmultiplied pagesby thatover transcludea it'''b'''illion.)}}
<ref group=note>For instance, [[Module:Asbox]] is transcluded on about 2 million pages, which each have Asbox using Buffer functions on 10-30 variables, some of which may be strings generated by other Modules that may eventually use Module:Buffer several times. Finally, throw in the fact that many pages transclude Asbox multiple times, and you can see how a few microseconds per op could translate to hours for the [[Help:Job queue|job queue]].</ref>}}
 
{{Module rating |release<!-- Values: pre-alpha • alpha • beta • release • protected -- If a rating not needed/relevant, delete this template call -->}}
<!-- Please place categories where indicated at the bottom of this page and interwikis at Wikidata (see [[Wikipedia:Wikidata]]) -->
{{TOC right}}
 
This module was originally developed to optimize string concatenation in [[Module:Asbox]] but can be used in any module.
 
Line 25 ⟶ 26:
 
{{luaself|\|args=sep, i, j}}{{anchor|call Buffer object}}
:''See also {{luaself|:_str|plain=y}} for advanced string conversion.
 
Get Buffer as type {{luaref|string||y}} by performing a function call on the Buffer ''object'' (as opposed to [[#require'Module:Buffer'|a call on the ''Module'']]). Calling a Buffer is basically shorthand for {{luaref|table.concat|args=Buffer, ...}}, or, with no args, {{luaref|tostring|args=Buffer}}.
Line 31 ⟶ 32:
However, if your Buffer contains [[#raw|raw]] objects or out-of-sequence values, then the return string would be the result of {{luaself|Buffer|:_all|empty-buffer:_all|args=Buffer )( ...}} instead.<ref group=note name=raw />
 
{{anchor|===Buffer.last_concat}}===
 
{| style='border-collapse:collapse'
When strung without a separator, the result may be retrieved via {{code|Buffer.last_concat}}. Future tostring operations on the Buffer will return Buffer.last_concat until it is modified.
|{{TOC tab|'''Buffer.last_concat<small><br/>Caching behavior and how to 'purge'</small>'''|Caching behavior and how to 'purge'|depth=4}}
 
|}
When strung without a separator, the result may be retrieved via {{code|Buffer.last_concat}}. Future tostring operations on the Buffer will return Buffer.last_concat until it is modified. You may purge the cache by setting this key to nil, by appending a [[#valid|valid value]] and immediately/or removing ita value: <code>{{luaself|:_|args=(0)|plain=y}}{{luaself|[[#Buffer|:_nil|:_nil|y|args=()}}]]</code>, as well as by passing an empty tablenothing to {{luaself|:_c|args={}() }}.
 
===Buffer:_===
 
{{luaself|:_|args='string'|args2=value, pos, raw|args3=value, raw}}
:''See also {{luaself|:stream|Stream modeplain=y}} for a faster, simpler version of this op.
 
Appends a value to the Buffer. In rough terms, {{code|lang=lua|Buffer:_'string1':_'string2'}} is the same as {{code|lang=lua|Buffer {{=}} Buffer..'string1'..'string2'}}. (It may help to imagine {{code|:_}} as a {{code|..}} that has stood up and is now casting a shadow.)
Line 49 ⟶ 50:
* {{luaref|nil||y}}
* empty {{luaref|string||y}}
* {{luaref|table||y}} without a {{luaref|Metatables|__tostring metamethod}} and which <{{code>''|table''[1]</code>|lang=lua}} is nil or false.
 
A table with no __tostring will pass through {{luaref|table.concat}} before insertion. An {{luaref|error|plain=y}} may be thrown if the table would cause table.concat to error. (Use {{luaself|:_all}} instead for such tables.) For all other ''value'', the result of {{luaref|tostring|args=value}} would be inserted so long as it is not an empty string.
 
For all other ''value'', the result of {{luaref|tostring|args=value}} would be inserted so long as it is not an empty string.
 
{{anchor|raw}}
Set {{code|raw}} to true to force ''value'' in Buffer without tostring coercion, including [[#no-op|invalid]] values.<ref group=note name=raw>Setting a Buffer to ''raw'' incurs [[#performance|performance]] penalty for all future tostring ops as it must re-validate each indexed value through {{luaself|:_all}} to a new table before passing that to table.concat (vs. passing itself directly). That said, re-stringing a raw Buffer is still usually several times faster than using the {{luaref|Concatenation operator|..}} op to join an equivalent number of strings. (See [[#Tips]] for ways to avoid using raw)</ref>
 
When passed {{code|pos}} of type {{luaref|number|plain=y}}, the argument is identical to ''pos'' for {{luaref|table.insert|args=table, pos, value}}. In fact, assuming a [[#valid|valid value]], {{luaself|:_|args='string', 1}} is exactly the same as {{luaref|table.insert|args=Buffer, 1, 'string'}}.
 
Unconventionally, a ''pos'' of type {{luaref|string|plain=y}} is treated as relative to length; that is, {{luaself|:_|args='string', '-1'}} is equivalent to {{luaself|:_|args='string', #Buffer - 1}} (obviating the need to set a {{luaref|Local variable declarations|local|y}} Buffer to use the {{luaref|Length operator|length operator|y}}). If given only two (non-self) arguments with the second being a boolean, then the second is read as ''raw'' instead.
 
{{anchor|raw}}
Set {{code|raw}} to true to force ''value'' in Buffer without tostring coercion, including [[#no-op|invalid]] values.<ref group=note name=raw>Setting a Buffer to ''raw'' incurs [[#performance|performance]] penalty for all future tostring ops as it must re-validate each indexed value through {{luaself|:_all}} to a new table before passing that to table.concat (vs. passing itself directly). That said, re-stringing a raw Buffer is still usually several times faster than using the {{luaref|Concatenation operator|..}} op to join an equivalent number of strings. (See [[#Tips]] for ways to avoid using raw)</ref> If given only two (non-self) arguments with the second being a boolean, then the second is read as ''raw'' instead.
 
===Buffer:_nil===
Line 76 ⟶ 75:
===Buffer:_all===
 
{{luaself|:_all|args={ value, ... }|args2={ value..., value {{=}} pos, functionName = args, ... }, nanKeys}}
 
Takes a table {{code|value}}, iterates through all number keys {{luaref|table.sort|in order|plain=yes}}, appending each [[#valid|valid]] value to the end of the Buffer. In contrast to {{luaref|ipairs}}, the iterationthis starts at the most negative key (down to {{luaref|math.huge|-inf|y}}), continues through any nil keys, until it reaches the most positive index and includes [[Double-precision floating-point format|non-integer number keys]]. (Note: despite Module:Buffer.__pairs having a more thorough iteration than ipairs, the runtimedifference ofin Module:Buffer'stheir iteratorruntimes is almost statistically indistinguishable from that of ipairsinsignificant. Details at [[#Performance]] and [[#Using the iterator outside of buffer]].)
 
A table ''value'' that has no metatable will have its contents iterated by this function before moving on to the next value. All other data types are processed by {{luaself|:_}}.
 
{{anchor|nanKeys}}
TheBy iterationdefault, this excludesignores non-number keys unless {{code|nanKeys}} evaluates true. HoweverIf so, keep in mind non-number keys are iteratedprocessed after number keys. Keep in mind such keys are iterated in {{luaref|next|no particular|y}} order, though an order may be imposed by wrapping each pair in a table indexed at a number key.
 
If thegiven a <ucode>''value'' = ''pos''</ucode> atpair, thedefined index is eitheras a number or a number string thenindexed theat ''key''a andnon-number ''value''key, then pairsthey will be passed as the {{code|value}} and {{code|pos}} argumentarguments offor {{luaself|:_|plain=y}}, respectively. Thus, {{luaself|:_all|args=({1,2,3,'... done',[3.5]=variable and 4 or {four='1',zero=1{{))}},true)}} produces the same result as:
{{#tag:syntaxhighlight|Buffer:_(1):_(2):_(3)
if variable then
Line 94 ⟶ 93:
Buffer:_'... done'|lang=lua}}
 
If thea ''nanKey''non-number iterationkey encounterspoints to a value that cannot be coerced into a {{luaref|tonumber|coerced into a number|y}} andthen whichthe ispair notmay boolean,be then,treated if theas <code>''keyfunctionName'' matches= the''args''</code>, namewhen of''functionName'' matches a Buffer object function, theand match''args'' willis benot calledboolean. TheIf arguments,''args'' ifis such that {{code|value[1]|lang=lua}} evaluates true, then this will bepass the return of {{luaref|unpack|args=value, 1, table.maxn(value)}} to the named function; otherwise, the value is passed as is.<ref group=note>In other words, if the value''args'' is a non-number string or a table without [1] set, the valueit will be passed as the only argargument. AFurther functionnote it is not possible to pass a <code>''functionName'' = ''args''</code> pair where ''args'' is numerical since such would be read as <code>''value'' = ''pos''</code>. Finally, passing a function type as ''args'' will throwsthrow an error message.</ref> For example:
 
{{code|1=p(_G,'arg', true):_all({'arg',arg==true and {'==true: ' ,_in={_G, 't', nil, ' awesome'}{{))}}, true):_(t and {t(), t..'r', t..'st'})|lang=lua}}
Line 106 ⟶ 105:
Creates and returns a new Buffer object. This does not <u>not</u> append the new Buffer to the parent. (See next section)
 
More precisely, it re-calls the {{luaself|Buffer|[[#require'Module:Buffer'|Module:Buffer|y}}]] instance which created the Buffer object with the passed arguments and then adds a reference in thefor new Buffer thatto allowsallow it to retrieve its parent.<ref group='note' name='in-dependents'>However the parent will not contain a reference to the child. Calling {{luaself|:getParent}} on the child without first referencing it with either the [[#global functions]] or a local variable will cause the child to become irretrievable. This is intentional as setting a reference would prevent {{luaref|Garbage collection}} on child Buffers that have no futher purpose.</ref> Do not pass _G if the Module:Buffer instance was not initialized with [[#Global functions|global functions]] enabled.
<ref group='note' name='in-dependents'>There is no 'getChild' method. If a child needed after returning to the parent, set it {{luaref|Local_variable_declarations|locally|y}} (or use {{luaself|:_G}}) prior to returning. (No, {{u|Codehydro}} did not get lazy. Rather, this allows {{luaref|Garbage collection|garbage collection|y}} on children with no further purpose.)</ref> Do not pass _G if the Module:Buffer instance was not initialized with [[#Global functions|global functions]] enabled.
 
Note that all Buffer parent references are {{luaref|weak tables|weak|y}}. If a variable is set to the parent and then set to something else, such may trigger immediate garbage collection.
 
===Buffer:_out===
 
{{luaself|:_out|args=sep|args2=outs, sep-{{ndash}}list, { default-{{ndash}}sep, ..., [out] = sep, ... } }}
 
{{luaref|table.concat|Joins|y}} Buffer with {{code|sep}} and appends result to the parent Buffer. Returns the parent. If no parent is found, this is a no-op and returns the same Buffer.
 
If given more than one (non-self) argument, then the first is read as {{code|outs}}{{--}}the number of :_out() operations to perform.<ref group=note>The first argument is not type checked. For [[#performance]], it is read as ''outs'' only when there are multiple varargs. In shortother words, use {{luaself|<code>Buffer:_outs|args=''N'',_out(2)</code> nil}}will ifuse you<code>2</code> desireas tothe separator. To append ''N'' generations to their parent with no separator, use <code>Buffer:_outs(''N'', nil)</code>.</ref> Each additional argument in ''{{code|sep-list}}'' is applied as ''sep'' for that :_out operation. That is, the first ''sep'' applies to the current Buffer, the second to its parent Buffer, the third to its grandparent, and so on.
 
If the last vararg is a table, itsthen first index''table''[1] will be applied as the default keyseparator for all nil varargs in ''sep-list''. TheThis table may immediatelydirectly follow ''outs'' (i.e. ''sep-list'' may be omitted). If it contains other keys, then the value''sep'' ofat key ''N'' would beapply appliedfor asthe ''sepN'' for the Nthth :_out() instead of ''default-sep''. Thus, making the followingthese two snippets equivalentare synonymous: {{luaself|:_out|args=4, nil, nil, nil, ' and ', {', '} }} and {{luaself|:_out|args=4, {', ', [4] = ' and '} }}. AInclude false index signifies thatin ''default-sep-list'' shouldto notindicate beno usedseparator applies for that generation''out''.<ref (angroup=note>An empty string willwould doproduce the same) output as false, however, Lua strings, even empty ones, take up memory until garbage collected.</ref>
 
===Buffer:_str===
 
{{luaself|:_str|args=sep|args2=generations, sep-{{ndash}}list, { default-{{ndash}}sep, ..., [generationgen] = sep, ... } }}
 
Joins a Buffer with {{code|sep}} and returns the string. Varargs are handled by the same function as {{luaself|:_out}}, which, if provided, this will create a new temporary Buffer and backtrack the number of {{code|generations}} specified, inserting each ancestor in front of its descendants in the temporary Buffer. The ''sep'' indexed at {{code|generations + 1|lang=lua}} will be used as the joiner for the temporary Buffer (unless the first ancestor is reached before the specified number of generations, in which case it is the index following that of the original generation).
 
Unlike :_out, this does not append the child into the parent. As such, even with the same arguments, it may return a different result than would be obtained from stringing the return of :_out since each parents' ''sep'' is not used to join parent and child. Furthermore, the number of ''generations'' counted includes the current Buffer, whereas the number of "''outs''" in Buffer:_out does not.
 
===Buffer:_parent===
 
{{luaself|:_parent|args=outs, sep-{{ndash}}list, { default-{{ndash}}sep, [out] = sep, ...} }}
:''To skip generations without breaking the Buffer chain, see [[#global functions]].
 
Similar to {{luaself|:_out}} except, instead of apending the Buffer to its parent, this calls {{luaself|:_str}} on the parent(s) and appends the result. The parent is unaffected by this operation and may still be retrieved via {{luaself|:_out}}.
 
===Buffer:getParent===
 
{{luaself|:getParent|args=...value|args2=functionName, ...}}
 
Returns parent Buffer, or, if none exists, sets a newly created Buffer as the 'parent' and returns the adopted parent.<ref group=note>Note, as though it created the child with {{luaself|_in}}, the parent contains no reference to the child. See also: <ref group='note' name='in-dependents'/></ref>
 
Following this Module's waste no {{code|()}} philosophy, arguments are passed to the parent. If passed only one {{code|value}}, this is equivalent to {{luaself|Buffer|:_|***:getParent():_|args=value}}.
If any {{luaself|varargs|plain=yes}} are given, {{code|functionName}} must be a string naming a Buffer object function (or [[#library]]) to be called on the parent using the varargs.
 
Also know that here is no 'getChild' method.<ref group='note' name='in-dependents'/>
 
===Buffer:killParent===
 
{{luaself|:killParent|args=...}}
 
Unsets the parent reference, allowing {{luaref|garbage collection||y}} unless there are non-weak references to the parent.
 
If passed any args, they will be passed to the current parent via Buffer:getParent as a "parting gift". In either case, returns to current Buffer.
 
===Buffer:_c===
Line 142 ⟶ 158:
{{luaself|:_c|args=clear|args=clear, copy}}
 
Nils all keys of the table referenced by {{code|clear}} and unsets its metatable. If passedno antable emptyas table''clear'', this simply purges the cache at {{luaself|.last_concat}}.
 
If given a table to {{code|copy}}, itthis will also duplicate all key-value pairs of ''copy'' into ''clear'', passing any value of type table through {{luaref|mw.clone}}. The former will also acquire the latter'sAny metatable, though,and ifBuffer ''copy''parent isand anraw {{luaref|HTMLreferences library|mw.htmlare object}}, [[#Buffer:_inHTML|Module:Buffer's augmented version]] would be setalso insteadcopied.
 
If ''copy'' is not a table, then it will be inserted as the first index of the ''clear''ed table so long as ''copy'' is not nil or false.
 
==Stream mode==
===Buffer:stream===
 
{{luaself|:stream|args='string'|args2={concat-{{ndash}}list}|args3=(var)}}{{anchor|streaming|calling a Buffer:stream}}
 
Switches the Buffer to stream mode. In this mode, the [[#call Buffer object|Buffer call]] operation, instead of returning a string, now acts as streamlined version of {{luaself|:_}}.
 
When streaming, you may append a sequence of stringsstring (and table) literals with nothing between them (or only {{luaref|Character class|ASCII space chars|y}} if desired). For example, both A and B will produce identical strings:
{{#tag:syntaxhighlight|local A = p:stream'A string of text may flow''with nothing between each string' 'or perhaps only a space'
{{#tag:syntaxhighlight|
'or even tab and line-break characters''and continue to append individually''for use with a joiner'
local A = require'Module:Buffer':stream'A string of text may flow''with nothing between each string' 'or perhaps only a space'
'or even tab and line-break characters''and continue to append individually''for use with a joiner':_str' '
 
local B = require'Module:Buffer'p:_'A string of text may flow':_'with nothing between each string' :_ 'or perhaps only a space'
:_'or even tab and line-break characters':_'and continue to append individually':_'for use with a joiner':_str' '
 
=mw.dumpObjectlogObject{A, A==B, A:_str' '}
table#1 {
"A string of text may flow with nothing between each string or perhaps only a space or even tab and line-break characters and continue to append individually for use with a joiner",
true,
"A string of text may flow with nothing between each string or perhaps only a space or even tab and line-break characters and continue to append individually for use with a joiner",
}|lang=lua}}
 
Aside from saving two characterskeystrokes per string, this mode runs about [[#performance|50 percent faster]] than :_ (which says a lot considering :_ is much faster than the .. op). Despitefor thelong lack of any operator between each call, this is still a {{luaref|Function calls|function call|y}}; in other words, you must still wrap numbers and variables in parentheses {{code|()}}.<ref group=note>Instead of passing a number type, pass a number string (i.e. {{code|lang=lua|Buffer:stream'1'}} instead of {{code|lang=lua|Buffer:stream(1)}}). Such improves performance (and is more aesthetically pleasing in this modestrings).</ref>
Also, Lua numbers
<ref group=note>It is best practice to pass number ''strings'' instead of a passing a number literals (i.e. {{code|lang=lua|Buffer:stream'1'}} instead of {{code|lang=lua|Buffer:stream(1)}}). Such improves performance (and is more aesthetically pleasing in this mode).</ref>
and named variables are too shy to [[skinny dip]] in a Buffer stream and must wear parenthesis {{code|lang=lua|()}} as with any {{luaref|Function calls|function call|y}}.
 
===='''Returning to normal mode===='''<br/>
No explicitspecial action is needed to exit streamthis mode. The normal call to string op is restored upon the use of any regular Buffer function or any operation which coerces the Buffer into a string.
 
 
Line 178 ⟶ 196:
===Buffer:_inHTML===
 
{{luaself|:_inHTML|args=tagName, args|args2={ args{{ndash}}list } }}
Creates an augmented {{luaref|HTML library|mw.html object}}. The arguments are identical to that of {{luaref|mw.html.create}}.
 
Creates and returns a [[#Buffer-HTML|modified mw.html object]]. Accepts the same parameters as {{luaref|mw.html.create}}.
Enhancements are as follows:
* Allows {{code|..}} op to be used on Buffer-mw.html objects directly (no {{luaref|tostring}} needed).
* If initialized, will store tags and wikitext in an Element-Buffer, with which you may use Module:Buffer object functions to append (and remove, etc.) values.
* Element-Buffer objects may use {{luaself|Buffer|Element-Buffer:_add}}, which greatly reduces the code size needed to build an equivalent mw.html object.
 
Modifications are summarized below:
===HTML-Buffer===
* The {{code|..}} may be used on Buffer-mw.html objects directly (no {{luaref|tostring}} needed).
* If [[#HTML-Buffer|initialized]], will store tags and wikitext in an Element-Buffer, with which you may use Module:Buffer object functions to append (and remove, etc.) values.
* Element-Buffer objects may use {{luaself|pre=Element-|:_add}}, which greatly reduces the code size needed to build an equivalent mw.html object.
 
Unlike mw.html.create, if {{code|args}} has keys other than <code>args.parent</code> and <code>args.selfClosing</code>, it will pass through {{luaself|pre=Element-Buffer|:_add}} for further processing. Moreover, if passed a table where mw.html.create expects ''tagName'', this treats it as ''args'' instead.
{{luaself|Buffer|HTML-Buffer|args='string'|args2={ wikitext, { tag = { tagName, arg = value, wikitext, htmlFunction = args, tag = tagName } }, ..., attr = { name = value } } }}
 
Most mw.html functions are unchanged, except {{luaref|mw.html:tag|:tag}}, {{luaref|mw.html:done|:done}}, and {{luaref|mw.html:allDone|:allDone}} are embedded in a wrapper function that checks whether they return a normal mw.html object. If so, converts it to a Buffer-HTML object and sets a parent reference.
<ref group=note>Buffer(-HTML) objects reference their parent differently from mw.html objects. Passing a normal mw.html object to Buffer:_inHTML as {{code|args.parent}} and then calling {{luaref|mw.html:done|:done}} the object created, followed by {{luaself|:getParent}} on the adopted parent, may return the "child." This is a feature rather than a bug.</ref>
 
Note that other functions in section [[#HTML extension]] are only available after Buffer:_inHTML is used for the first time.
 
===Buffer-HTML===
 
{{luaself|\-HTML|args='string'|args2={ wikitext{{ndash}}string, { tag = { tagName, arg = value, wikitext, htmlFunction = args, cssName = cssValue } }, ... } }}<br />
 
Buffer-HTML objects may be used like any mw.html object. (In fact, if the only change were to substitute {{code|mw.html.create}} with {{code|require'Module:Buffer':_inHTML}} in an existing Module, its output should remain the same.)
 
Call the object as a function to return its {{luaself|pre=Element{{ndash}}|\|plain=y}}, which is the table found at {{code|mw.html{{ndash}}object.nodes}} converted into a Module:Buffer object.
 
Strings are passed to the Element-Buffer via {{luaself|:_}} which basically has the same effect as though <code>:wikitext</code> were between {{code|Buffer-HTML}} and {{code|lang=lua|'string'}}, the only difference being the object returned. Tables are passed to {{luaself|pre=Element{{ndash}}|:_add}}.
 
Most Buffer object functions are either unavailable for use directly on the Buffer-HTML object. Those listed below have been modified so that
 
===Element-Buffer===
 
{{luaself|pre=Element{{ndash}}|\|args=sep, i , j}}
 
Element-Buffers have the same metatable as normal Buffer objects, so [[#call Buffer object|calling it]] will string it in the same manner.
 
The string returned is analogous to the value returned by the [http://www.w3schools.com/jsref/prop_html_innerhtml.asp "innerHTML"] DOM property in [[JavaScript]]. In other words, when strung, it is the contents of the Buffer-HTML object without the "outerHTML" or tag.
 
You may use most Buffer object function normally, however those which have a Buffer-HTML version (such as {{luaself|\-HTML:_out}}) will instead behave as though used on the [[#Buffer-HTML|outer HTML object]].<ref group=note>While Buffer-HTML objects may use [[#global functions]], there is no separate Buffer-HTML version. In other words, the self-action of a global function on an Element-Buffer is <u>not</u> redirected to the outer Buffer-HTML object.</ref> Also, {{luaself|pre-Element|:_inHTML}} has been modified as described in that section.
 
Additionally, you may chain any mw.html object function directly on an Element-Buffer. With the exception of {{luaself|pre=Element{{ndash}}|:tag}} and {{luaself|pre=Element{{ndash}}|:done}}, the mw.html function has been placed in a wrapper function that merely redirects the self-action to the outside Buffer-HTML.<ref group=note>{{luaref|mw.html:allDone}} is doubly wrapped for Element-Buffers. The inner wrapper sets a Buffer parent reference as described at {{luaself|:_inHTML}}.</ref>
 
====Element-Buffer:done====
 
{{luaself|pre=Element{{ndash}}|\|args=dones}}
 
When called without arguments, this behaves just like {{luaref|mw.html:done}} as called on the outer HTML object.
 
However, it has been modified to accept {{code|dones}}, the number of :done() operations to perform. Thus, {{code|Element{{ndash}}Buffer:done(4)|lang=lua}} is equivalent to {{code|Buffer{{ndash}}HTML:done():done():done():done()|lang=lua}}.
 
Pass zero ({{code|lang=lua|0}}) as ''dones'' to return to the Element-Buffer's direct HTML container. (Using an mw.html function to no-op is another way to return to the Buffer-HTML object, e.g. {{luaself|pre=Element{{ndash}}|:node|args=()}}, though that example does not work for selfClosing tags.)
 
===ipairs with HTML-Buffer===
:''See also [[#Using 'all' pairs outside of buffer]] for more details about Module:Buffer's custom iterator.
 
<pre>
BufferHTML = p:_inHTML'td'{1,2,nil, '', true, 3,4,tag='br'}:done(0)
mw.log(BufferHTML)
for k, v in ipairs(BufferHTML) do mw.log(k,v) end
for k, v in ipairs(BufferHTML) do if v=='3' then BufferHTML():_nil(k) end end
mw.log(BufferHTML)
<td>1234<br /></td>
1 1
2 2
3 3
4 4
5 <br />
<td>124<br /></td>
</pre>
 
Converts the Buffer-HTML's holding table into an Element-Buffer Appends text or tags
 
==Global functions==
Line 197 ⟶ 270:
==Modified {{code|..}} operator==
{{code|Buffer .. value}}<br />
<code>''BufferedBuffer-HTML-object'' .. value</code><br />
This is akin to {{luaref|self=Buffer/doc|:_all|'''new-buffer'':_all|args={ Buffer, value} }} or <code>{{luaref|tostring||p|args=Buffer}} .. value</code>. HTML objects created by a Buffer may also be concatenated in this manner.
 
<code>''HTML-Buffer-HTML'' .. value</code><br />
 
 
Line 209 ⟶ 282:
==Using 'all' pairs outside of buffer==
 
{{anchor|library}}
==String, mw.ustring, and mw.text functions==
 
Line 214 ⟶ 288:
==Tips and style recommendations==
* If [[#Buffer|joining Buffer]] with a string immediately after <code>:_'<i>text</i>'</code>, place a space between 'string' and the [[#Buffer|separator]] and use double/single quote marks to . (i.e. <code>:_'<i>text</i>' " "</code> instead of <code>:_'<i>text</i>'{{`}} '</code> or <code>:_'<i>text</i>'(' ')</code>)
* Saving Module:Buffer locally, e.g. <code>local Buffer = {{luaref|require|args='Module:Buffer'|plain=y}}</code>, though fine, is often unnecessary since all Buffer objects can create new buffers via {{luaref|self=Buffer/docluaself|:_in}}.
 
 
Line 226 ⟶ 300:
 
* Appending values in multiple locations is one of the primary reasons why the [[#nanKeys|nanKeys]] argument exists. While passing a boolean directly will cause an error, you can do something like...
::this:{{sp|3}}{{code|lang=lua|1=Buffer:_all({condition and {_nil={'0', 'replacement'},Front=1,getParent='from child'{{))}}}, true)|lang=lua}}
::versus: {{code|lang=lua|Buffer:_nil('0', condition and 'replacement' or false):_(condition and 'Front', 1):getParent(condition and 'from child'):_B(child)}}.
 
Line 234 ⟶ 308:
* Inserting a [[#Buffer:_G|named]] empty table is raw as a placeholder to be populated later via this function may be easier than calculating ''pos'' argument of {{luaself|:_}}.
 
'''For {{luaself|:_inHTML}} '''
 
* When appending simple HTML structures, something like {{luaself|:_|args=mw.html.create'br'}} is roughly 6 times more efficient than <code>{{luaself|:_inHTML|plain=y}}<syntaxhighlight lang=lua enclose=none>'br':_out()</syntaxhighlight></code>, at least in terms of server CPU usage. (Though {{code|lang=lua|Buffer:_'<br />'}} is 25 and 4 times more efficient, respectively. Also note that Buffer:_inHTML is slower on the first run due to initialization. After the first run, the efficiency ratio of using mw.html.create directly over Buffer:_inHTML drops to 2.)
 
{{anchor|performance}}