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!
===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}}
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