Editing
Module:Buffer/doc
(section)
From Thetacola Wiki
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Loadable convenience extensions== The methods here are loaded on demand or depend on subroutines which need initialization. These methods can greatly simplify the structure of the modules which employ them by doing, in a fluent manner, many tasks which may otherwise force an awkward interruption in Buffer call chains. {{anchor|gfuncs}} ===Global functions=== Methods such as {{luaref|mw.html:done}} and {{luaself|:getParent}} traverse a node tree in only one direction. While fine for returning to an ancestor, they do not provide navigation to a non-ancestor (often necessary for templates with co-dependent parameters). Yet, repeated breaks in call chains to set local variables for several nodes of the same branch can look choppy if not confusing for nodes many generations removed from its declaration statement.<ref group="note">i.e., does ''x'', in the following, reference the TD or some other node hidden within an [[ellipsis]]?: {{code|lang=lua|local x {{=}} mw.html.create():tag ... :tag'td' ... :tag(arg and 'div' or 'p'):wikitext( ... ):tag'br':done():done() }}</ref> Templates with several conditionally-appended nodes with similar, but not identical, parts may present another conundrum for coders who must decide between having awkward call chain interruptions to store potentially repeated components as local variables or constructing a somewhat redundant module that is more susceptible to maintenance errors by future editors who may patch one code segment but miss the sibling buried within a convoluted nesting of {{luaref|Logical operators|logical operators|y}}. This module's global functions and added [[syntactic sugar]] for the [[#G object|_G object]] were formulated to simplify such node trees with multi-conditional or repeating structures by providing concise in-chain variable declaration. The extension is enabled by passing your global table to the module{{--}}either in the initial call to [[#initialize|require'Module:Buffer']] (more instructions in that section) or to {{luaself|:_in}} which forwards arguments to Module:Buffer.<ref group="note">Global function are not enabled by default for various reasons: * Most templates are one-dimensional (i.e. contain few if any nested conditional statements) and thus would not benefit from these methods. * Loading them to the Module:Buffer meta index means more items that must be sifted through each time a specific function has to be retrieved. * Lua checks the global scope last; thus retrieving values from that scope takes longer than it would if they were stored in the local scope. * Excess use may clutter the global scope enough to slow access to basic Lua functions (e.g. {{luaref|type}} or {{luaref|pairs}}) even after Buffer methods are no longer used. It should be mentioned however that variable retrieval even even in a relatively cluttered global scope is fairly trivial. In fact, early versions of Module:Buffer used globals extensively (and actually had no locals declared before the final return, or rather the entire module was just one long return statement). In contrast, the current version nests many {{code|lang=lua|do ... end}} blocks to limit scope size. Yet, {{luaself|:_}}, a core function which has changed little, is only a modest 10 percent faster than itself in the last unscoped version (not published); then again, perhaps the benefit of scope dieting has been masked by much greater total number of variables required by new features?</ref> ====Buffer:_G==== {{luaself|:_G|args=name, save}} {{distinguish|text=the [[#G object|§ _G object]], which chain call looks the same but may behave differently.}} Pass <code>name</code> and <code>save</code> to assign the object passed as ''save'' to a global variable via {{luaref|rawset|args=_G, name, save}}.<ref group="note">Actually, the first argument to rawset is a local variable <code>[[#new_G|new_G]]</code> which generally equals _G but not always, to be detailed in a later section.</ref> Pass only ''name'' and this substitutes ''self'' for ''save'' to assign the Buffer object to <code>_G[name]</code> instead. Give an explicit nil as ''save'' to unset a global. This returns the Buffer object as well as any argument given after ''name''. This is a no-op when ''name'' is nil or a boolean, or, when ''save'' (eventually) evaluates true and {{luaref|rawequal|args=save, rawget(new_G, name)}} also returns true. {{anchor|metaglobal}} If the named global already exists, this "backs up" the old value by moving it to the meta __index of the global table, setting a new metatable if none exists.<ref group="note">If the meta global has an __index which is a function (as is the case after requiring [[Module:No globals]]), the back-up op aborts without throwing an error.</ref> Retrieving the old value requires unsetting the new one via {{luaself|:_R}} (more details in that section). If overwritten a third time, the first value is discarded and the second takes its place in the back up. If a metaglobal variable exists but the global is nil, this sets the global without unsetting the metaglobal (i.e. does not back up a nil global). An exception is when this is given an explicit nil as ''save'' and only the metaglobal exists; thus, passing nil twice for the same ''name'', unsets the key in both the global table and its metaindex. ====Buffer:_R==== {{luaself|:_R|args=name, save|args2='new_G', var, metaindex}} This {{luaref|rawset||y}} with the global table as the first argument and <code>name</code> and <code>save</code> as the second and third, respectively, returning the Buffer object for call chaining.<ref group="example">The following demonstrates how, by combining Buffer:_R and Buffer:_G, the global variable ''v'' can be declared, backed-up and replaced, replaced without back-up, restored from back-up, and removed completely: :{| |{{#tag:syntaxhighlight|require'Module:Buffer' (_G,'v') -- call module with global functions enabled and declare new buffer as v :_'A' -- append 'A' to the returned buffer :_G('v', 1):_(v) -- _G.v = 1, shift old value (the buffer) to metaglobal.__index :_R('v', 2):_(v) -- _G.v = 2, discard old value (1) without back-up :_R'v':_(v) -- unset _G.v, which now defaults to metaglobal.__index.v (the buffer) :_G('v', nil)", " -- remove back-up and join the buffer with a separator ..' and '..tostring(v)-- returns 'A, 1, 2, A12 and nil'|lang=lua}} |}</ref> This is a no-op if ''name'' is nil or a boolean. {{anchor|new_G}} {{see|#new_G object}} Note that Buffer methods use a local variable <code>new_G</code> as a proxy for the global table _G; though not a global index, the string {{code|lang=lua|'new_G'}} is a "magic word" that changes the destination for future ''save'' for this and Buffer:_G. Pass a table as <code>var</code> (same place as ''save'') to set as the ''new'' new_G. Any table such that {{code|lang=lua|1=var._G == _G}} is treated as a (former) new_G object. This {{luaref|getmetatable|gets the metatable|y}} of former proxies and {{luaref|setmetatable|sets a new table|y}} with the {{luaself|_G object|plain=y}} __call method on non-new_G tables. Then, this, if third parameter <code>metaindex</code> equals: * nil {{--}} backs up the current proxy as the metaindex of the next (though this no-ops if ''var'' equals new_G to avoid cyclical indexing). * false {{--}} leaves the metaindex intact (replacing the current proxy without back-up) * true {{--}} unsets the metaindex of the next proxy * any other value {{--}} sets that value as the metaindex of the next proxy. (Note new_G._G is not set until it is returned by {{luaself|:_2}}) To omit or to pass nil/false as ''var'' has the same effect as {{luaself|:_R|args='new_G', {} }}. Pass true instead and this treats it as though passed as ''metaindex'', creating a new proxy without backing up the incumbent. ====Buffer:_2==== {{luaself|:_2|args=name, save|args2='new_G', ...}} This returns the value indexed at key <code>name</code> in the global table. If it does not exist, this forwards both arguments to {{luaself|:_G}} and returns the saved value (which may be itself). In other words, {{luaself|:_2|args=name, save}} is roughly equivalent to {{code|lang=lua|1=_G[name] = _G[name] or save or save==nil and Buffer}}. The string {{code|lang=lua|'new_G'}} will return the Module:Buffer local variable <code>[[#new_G|new_G]]</code>, used as a proxy for the global variable _G. Given more than one argument, this forwards arguments to {{luaself|:_R}} to assign another proxy global before returning the (newly-deposed) proxy. This then sets <code>new_G._G</code> to the original _G object for call chaining. (See § chain call in [[#G object|_G object]]). ====Buffer:_B==== {{luaself|:_B|args=var}} Takes only one argument and returns that argument. Assuming the only ''X'' declared is {{luaref|_G|_G.X}} and new_G equals _G, then {{luaself|:_B|args=(X)}} and {{luaself|:_2|args='X'}} are equivalent.<ref group=note>Dubbing this a "global function" is bit of a misnomer since this never retrieves anything from the global table. While designed for in-chain navigation to Buffer objects that were [[#Buffer:_G|self-declared as globals]], this returns any local reference or literal passed as well (allowing {{luaself|pre=Element-|:_add}} to execute Buffer methods on non-Buffer objects <code>[[#args.globalFunction|args._B]]</code>).</ref> When passed a variable that does not exist, this returns the Buffer nil object: {{anchor|Buffer-nil}} =====Buffer-nil object===== {{luaself|\-nil()}}<br /> {{luaself|\-nil:anyName|args=():_B( var )}} The Buffer-nil object is unique. Calling this as a function returns nothing (in contrast, calling an empty Buffer object returns an empty string). This does however have the Module:Buffer __concat metamethod, which treats this the same way as any [[#invalid|invalid]] object (i.e. ignores it). Appending this via {{luaref|mw.html:node}} or {{luaself|:_}} has the same effect as appending nil. Passing this to {{luaref|tostring||y}} returns nil instead of the string 'nil'. The only real Buffer method in its meta __index is {{luaself|:_B}}, however, any non-numerical key string retrieves a function that only returns the Buffer nil object for call chaining. In a sense, you can think of {{code|lang=lua|Buffer:_B(var):...}} as an {{code|lang=lua|1=if var~=nil then var:...}} block around the following chain that ends in the next :_B(). If {{luaref|mw.clone|cloned|y}}, the clone will be a normal Buffer object. {{anchor|_G object}}<!--anchor below excludes the _ --> ====_G object==== The first _G variable [[#initialize|passed to this module]] is given a __call metamethod that self-{{luaref|rawset||y}}s and returns in a manner that depends on whether it was called directly or from a chain.<ref group="example">Saving a new_G object globally via a chain call can prevent conflict. The follow example has a hypothetical "Module:X" that may overwrite globals declared by your module or unwittingly discard your new_G when it passes _G to Module:Buffer (passing _G to this module resets new_G to the global table even when the global functions are already enabled): :{| |{{#tag:syntaxhighlight| return require'Module:Buffer'(_G)--Return before require to show intent to return a Buffer object; chain cannot be broken :_R(frame.args.title and --store values outside global scope if invoked with title parameter 'new_G') :_G'myBuff' --save current Buffer in new_G :_2'new_G' --retrieve new_G :_G'my_G' --save new_G as global my_G :_G('t', --save title object as my_G.t for later re-use mw.title.new(frame.args.title or frame.args.page) ).myBuff --go to my_G.myBuff (my_G lacks the Buffer:_2 method, but doesn't need it) :stream(my_G.t.exists --just arbitrary code to show how in-line storage may be used without breaking the chain or warning(my_G.t), --local function warning() declared before return require'Module:X'.main(my_G.t), my_G.t.isSubpage and subpage(my_G.t), ... ) :_R('new_G', my_G) --set my_G as new_G again and have the new_G from Module:X as its metaindex :_(frame.args.detail and my_G.info :_(frame.args.detail)--append Buffer object from Module:X's new_G.info if args.details and it exists; append detail param to result or my_G.summary) --just append summary from Module:X if not invoked with detail param. :_B(t and --use global t as a shorthand for "if not frame.args.title then" (t only declared a global in line 2 if no title given) myBuff :stream(frame.args.page, frame.args.details2, mw.html.create'br', require'Module:Y'.main(frame)) or my_G.myBuff --place results in a table if invoked with title param (alternative chain call branches within Buffer:_B) :_inHTML'table'(_addArgs) :_parent() ) |lang=lua}} |}</ref> This module conserves any pre-existing metatable and alters no metamethod other than __call. :{| | =====direct call===== <code>_G( k, v )</code><br /> <code>_G'string'</code> When called, the _G object self-sets any string passed as <code>k</code> with whatever is passed as <code>v</code>. This returns ''v'', or nil if omitted (unlike with rawset, an explicit nil is not necessary to unset a variable with direct calls). Note that ''k'' must be a string to declare or unset a global in this op. Tables passed as the first argument are treated as though this were executed via a call chain (discussed shortly). Passing ''k'' which is not one of those two types will throw an error. =====chain call===== <code>chained-object:_G( k, v )</code><br /> <code>chained-object:_G'string'</code> {{distinguish|text=[[#Buffer:_G|§ Buffer:_G]], the Buffer object function, which differences are noted in the final paragraph of this section.}} When used in a call chain, this rawsets the ''k''ey-''v''alue pair in the chained object and returns that object. The _G object may chain itself when returning _G is desired for another op instead of ''v''. In contrast to the direct op, the in-chain op will index non-string ''k'' values. Moreover, this only unsets object[k] when passed an explicitly nil ''v''. If ''v'' is omitted in-chain, this uses the chained object as the missing argument; thus, (chained) <code>object:_G'string'</code> has identical effect and return to <code>_G('string', object)</code>. |} The same __call method is given to [[#new_G|new_G]] objects created by Buffer:_R, however the direct call only works if its metaindex is the _G object. Any table such that <code>table._G</code> points to the _G object may chain save to itself regardless of metaindex. Though the behavior of the chain op when ''v'' is omitted may be a [[Dead ringer (idiom)|dead ringer]] to that of [[#Buffer:_G|Buffer:_G]] when ''save'' is omitted and [[#new_G|new_G]] is the chained object, mind that the Buffer object function sets keys in new_G variable rather than the chained (Buffer) object; in other words, this is unaffected by Buffer:_R reassigning new_G to another table. Also, this does not have the back up behavior of Buffer:_G. {{anchor|Buffer-variable}} ===Buffer-variable object=== ====Buffer:_var==== {{luaself|:_var|args=var, change|args2={ ... }|args3=()}} Raw appends a Buffer-variable object, which may appear as a different value each time the object (or its container) is converted to a string.<ref group="example">The following contrived example demonstrates most features of {{luaself|:_var|plain=y}}: :{| |{{#tag:syntaxhighlight|local H, sep = require'Module:Buffer':_inHTML('div',{'Heading ',_var={nil,'odd','even'},color='blue',['text-decoration']='underline'}) :_out():_html(true):_html(true):_html(true) sep = H:_in'This is ':_var():_' - ':_var'A':_var(3,-1):_'\n' return H:_in(H(sep)):_(sep) :_'math:':_var():_'+ 5 =':_var(true,5):_';':_var():_out(0,' '):_var(false):_' - 1 = ':_var() --[[ produces: <div style="color:blue;text-decoration:underline">Heading odd</div>This is odd - A3 <div style="color:blue;text-decoration:underline">Heading even</div>This is even - B2 <div style="color:blue;text-decoration:underline">Heading odd</div>This is odd - C1 <div style="color:blue;text-decoration:underline">Heading even</div> This is even - D0 math: 0 + 5 = 5 ; 5 - 1 = 4 --]]|lang=lua}} |}</ref> Initialize a Buffer-variable object by passing as <code>var</code> a: * number - which, when strung the first time, appears as that number and reappears as <code>var + change</code> the next time it is strung. * string - that transforms into the next [[ASCII]] character via {{luaref|string.char||args=var:byte() + change}}. * table - to return the first (non-nil) item, then the second, and so on as determined by {{luaref|next|args=table}}, looping back to the first item after reaching the last. (Note the ''change'' argument does not apply to table-based Buffer-variables.) * custom function - to be set as the _build and __tostring method of a variable-object, though instructions for coding such functions are beyond the scope of this manual. Re-append the same variable object by passing {{code|lang=lua|true}} as the only argument. For non-table-based variables, you may specify ''change'' to append a sister object which transforms the value at the rate specified. Changes are cumulative. Thus, if the original is re-strung after a sister, its value will differ from that of its last appearance by the sum of the original and sister rates and vice versa. Apply a ''change'' without appending a new variable object to the Buffer by passing {{code|lang=lua|false}}. The shift is effective immediately and may affect previously appended variable objects not yet [[#Buffer:_out|finalized]]. Pass only false (i.e., omit ''change'') to produce the same effect as stringing the original once. Note that the false-change is the only ''change'' table-based Buffer variables will honor.<ref group="note">False cycles tables based on {{luaref|Length operator|#|y}} instead of {{luaref|next}}, which may diverge or error if the table contains nil items.</ref> Pass nothing to append a version which simply repeats the result of the last stringing. While generally identical in effect to the object generated by <code>:_var(true, 0)</code>, the Buffer-variable will return nothing if strung before any of its sisters. If passed an explicit nil as the first argument, this is no-op. If passed a boolean before any Buffer-variable has been initialized, this is also a no-op. Note that any op disables future caching at {{luaself|.last_concat|plain=y}} for all Buffer objects in your module (and in any module which may require it). {{anchor|library}} ===String, mw.ustring, and mw.text libraries=== ====Basic usage==== {{code|lang=lua|Buffer:functionName( ... )}} You may directly chain any function from the following libraries on Buffer objects: :{| |{{collist|colwidth=15em|style=width:49em| * {{luaref|String library|string|y}} * {{luaref|Text library|mw.text|y}} * {{luaref|Ustring library|mw.ustring|y}} }} |} Functions from these libraries added to the Module:Buffer metatable on-demand and placed within a wrapper method that strings the Buffer object for the first argument and then forwards the remaining arguments. Thus, the following are equivalent: {{code|lang=lua|Buffer:nowiki( ... )}} and {{luaref|mw.text.nowiki|args=tostring(Buffer), ...}} If a name exists in both the string and mw.ustring libraries, the string version takes precedence. You may [[prefix]] the letter ''u'' on any mw.ustring function{{--}}e.g. Buffer:ulen returns the number of unicode characters and Buffer:len returns the number of bytes. Buffer:gsub and Buffer:ugsub have a slightly different wrapper which substitutes the <code>repl</code> argument of {{luaref|string.gsub||y}} and {{luaref|mw.ustring.gsub||y}} when it evaluates false or is omitted with an empty string (otherwise the originals would throw an error). This saves a few keystrokes when removing characters via {{code|lang=lua|Buffer:gsub'[pattern]'}} as opposed to {{code|lang=lua|Buffer:gsub( '[pattern]', '' )}}. All other arguments are handled the same as with the other on-demand methods. Library functions which take a non-string as the first argument are not supported. ====Empty Buffer interface==== {{luaself|:_in|args=():functionName( ... )}} To obtain the first return value as a Buffer object (as opposed to whatever type the original normally returns), simply chain the imported method immediately after creating the new Buffer via [[#Buffer:_in|Buffer:_in]]. Only empty Buffer objects which have a parent object will append the result of their parent in this manner. This syntactic sugar allows two things: * For appending additional objects after the op via Buffer object methods. * For chaining multiple {{luaref|_|Scribunto|y}} methods not chainable to strings{{--}}e.g., this: {{code|lang=lua|1=Buffer:_in():uformat( ... ):_in():toNFD():encode'[<>#]':match'^(.-)==='}} : vs. the following which has the same order of operations albeit harder to see: {{code|lang=lua|1=mw.text.encode( mw.ustring.toNFD( Buffer:uformat( ... ) ), '[<>#]' ):match'^(.-)==='}} :{| | =====Special case: Element-Buffer===== {{code|lang=lua|empty{{ndash}}Element{{ndash}}Buffer:functionName( ... )}}<br /> {{code|lang=lua|Element{{ndash}}Buffer:_in():functionName( ... )}} The 'empty' behavior is different when chained to empty Element-Buffer or an empty child Buffer of an Element-Buffer. Library methods chained to an empty Buffer which parent is an [[#Element-Buffer|Element-Buffer object]] will instead string the grandparent [[#Buffer-HTML|Buffer-HTML object]] for use as the first argument before appending the result to the new Buffer. This interface is provided because Buffer-HTML objects, which are not true Buffer objects, are unable to load these functions, making this the only chainable option for Scribunto methods that includes the outer tag of non-empty Element-Buffers. Chained on an empty Element-Buffer, these methods will string the Buffer object which created its HTML tree via {{luaself|:_inHTML}}<ref group="note">Though this strings the same object returned by {{luaself|\-HTML:getParent}}, that function is not used to avoid setting a "lastHTML" reference.</ref> and append the result to the Element-Buffer.<ref group=example>Compare the comment and source: :{| |{{#tag:syntaxhighlight|--[[--= Result: ===> This is just a quick example to demonstrate a neat concept: <div>Notice how the same object is strung which allows you to recycle boilerplate text. <p>3 is 1 added to 2.</p> <span>Though this is not really realistic to be fair... Edit: not realistic at all</span> I hope such is much to your liking.</div> --]]--= Source: ===> require'Module:Buffer' '%s is %s to %s.'--A :_inHTML'div'():format('Notice how the same object', 'strung which allows you', 'recycle boilerplate text') :tag'p'():format(3, '1 added', 2) :done() :tag'span'():format('Though this', 'not really realistic', 'be fair..') :_in():sub(21, 29) :_('\nEdit:', 1) :_'istic at all' :_out() :done() :_parent()--B :_out'\n' :format('This', 'just a quick example', 'demonstrate a neat trick',--A 'I hope such', 'much', 'your liking')--B :gsub('trick.', 'concept:\n')|lang=lua}} |}</ref> |}
Summary:
Please note that all contributions to Thetacola Wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Project:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Navigation menu
Page actions
Module
Discussion
Read
Edit source
History
Page actions
Module
Discussion
More
Tools
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Search
Tools
What links here
Related changes
Special pages
Page information