Jump to content

Wikipedia talk:Lua: Difference between revisions

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia
Content deleted Content added
Line 697: Line 697:


Most of it can be done in wikicode... [[Public holidays in the United Kingdom#England, Northern Ireland and Wales]]. [[User:Cabayi|Cabayi]] ([[User talk:Cabayi|talk]]) 16:11, 4 September 2018 (UTC)
Most of it can be done in wikicode... [[Public holidays in the United Kingdom#England, Northern Ireland and Wales]]. [[User:Cabayi|Cabayi]] ([[User talk:Cabayi|talk]]) 16:11, 4 September 2018 (UTC)

== Do you have small Lua related tasks suitable for new contributors? ==

Hi everybody! Google Code-in (GCI) will soon take place again - a seven week long contest for 13-17 year old students to contribute to free software projects. Tasks should take an experienced contributed about two or three hours and can be of the categories Code, Documentation/Training, Outreach/Research, Quality Assurance, and User Interface/Design. Do you have any Lua / template related idea for a task (needs documentation, or some code / code changes) and can imagine enjoying mentoring such a task to help a new contributor? If yes, please check out [[mw:Google Code-in/2018]] and become a mentor! Thanks in advance! --[[User:AKlapper (WMF)|AKlapper (WMF)]] ([[User talk:AKlapper (WMF)|talk]]) 13:49, 9 September 2018 (UTC)

Revision as of 13:49, 9 September 2018

Ebola epidemy / lua error on ln.wiki

Hello, someone with IP copied medicall infoboxes from fr.wiki to ln.wiki to emprove the article about Ebola virus. Unfortunately, there are a lot of lua errors in the infobox. See here: https://ln.wikipedia.org/wiki/Bokono_ya_Ebola Can this be fixed? This is quiet urgent, as the article about Ebola is written by a medical doctor an in the lingala speaking area there is once again a Ebola epidemy. --Bombo (talk) 00:39, 24 May 2018 (UTC)[reply]

@Bombo: The immediate problem is that ln:Module:Wikidata does not have a formatStatements function. Module:Wikidata mentions that function is implemented at ruwiki but is not in the enwiki version. The fundamental problem is that a consistent set of templates/modules are needed. Editing ln:Bokono ya Ebola and looking under "Templates used on this page" shows what is being used and what might need to be updated for a consistent set. Johnuniq (talk) 00:58, 24 May 2018 (UTC)[reply]
@Bombo: The page with errors is apparently using templates/modules from frwiki which are not used at enwiki so asking at frwiki might be better if you do not want to switch to the enwiki system.
@Doc James: You have probably helped to translate Ebola virus disease in various places. Do you have an example that might be used as a model to fix the errors at ln:Bokono ya Ebola? Johnuniq (talk) 01:03, 24 May 2018 (UTC)[reply]
I no nothing about how to get Lua to work. User:RexxS might? User:CFCF installed the medical infobox in hundreds of languages. I do not know if they did ln.
Doc James (talk · contribs · email) 01:10, 24 May 2018 (UTC)[reply]
Ah here we go ln:Template:Infobox medical condition Doc James (talk · contribs · email) 01:11, 24 May 2018 (UTC)[reply]
Better [1] Doc James (talk · contribs · email) 01:12, 24 May 2018 (UTC)[reply]
Brilliant, thanks! I tweaked your link to the infobox CFCF set up in 2015. Johnuniq (talk) 01:23, 24 May 2018 (UTC)[reply]
Matando malámu, thank you very much! User:RexxS, User:CFCF, Johnuniq, Doc James --Bombo (talk) 13:43, 11 July 2018 (UTC)[reply]

Length of table inside code

Hello, is there any limit in table data ? I'm working on {{#invoke:IATA and ICAO code/Data‎|function}} and wondering if it would block if too large file? Thanks Bouzinac (talk) 07:36, 9 June 2018 (UTC)[reply]

The size is ok, but the style is not good. See Module:Convert/data and Module:Team appearances list/data for examples. I don't have time to say more at the moment but in a couple of days I could have a look at what is needed at Module:IATA and ICAO code/Data. Johnuniq (talk) 11:32, 9 June 2018 (UTC)[reply]
As John says, you are making work for yourself by trying to specify everything as a single element. Lua is very efficient at handling tables, so I would always recommend keeping the structure as uncluttered as possible. Perhaps John has a different idea, but I would suggest something like this to get data into the module, as it looks like each item has four pieces of data associated with it:
local p= {}
p.codetbl = {
--Australia/New Zeland/Oceania
	{ 'AAA', 'NTGA', 'Anaa Airport', 'Anaa' },
--Italy
	{ 'AHO', 'LIEA', 'Alghero-Fertilia Airport', 'Alghero' },
	{ 'ALL', 'LIMG', 'Riviera Airport', 'Albenga, Savona' },
	{ 'AOI', 'LIPY', 'Marche Airport', 'Ancona' },
-- and so on
}
You could then create whatever arrays you wished in this sort of way:
p.IATA = {}
p.ICAO = {}
p.WikiName = {}
for k, v in ipairs(p.codetbl) do
	p.IATA[v[1]] = v[3]
	p.ICAO[v[2]] = v[3]
	p.WikiName[v[1]] = v[4]
	p.WikiName[v[2]] = v[4]
end
The overhead in computation is really quite small because of Lua's efficiency with nested tables and it allows you generate reverse-lookup tables quite easily as well. You can make codetbl a local variable if you have no need to export it. This sort of scheme ought to be far easier to maintain and troubleshoot in any case. All of this is probably a bit late considering the amount of work you've already done, but it is something to bear in mind for the future. HTH --RexxS (talk) 12:36, 9 June 2018 (UTC)[reply]
I've added error messaging to your Module:IATA and ICAO code because it is nice to know why something isn't producing the expected results. The failed output of [[|]] is meaningless.
Do the data in Module:IATA and ICAO code/Data come from an official source that exists on the internet somewhere? If so, perhaps the correct thing to do is to do as I did for the various data tables required by Module:Lang. The data are periodically updated. To keep the lang data tables up to date I wrote a handful of small Lua modules that read data that I get from official sources. The helper module translates the source's format into a table that Module:Lang can use. For example, this html table is used to identify ISO 639-2 codes that have ISO 639-1 equivalents. Module:Language/name/data/ISO 639 synonym extraction tool reads that file and writes a Lua table that Module:lang uses. I copy the table from the source and past it into a sandbox page (because I do this periodically I have one set aside for the purpose). See [2]. Click Show preview to see the results.
Trappist the monk (talk) 13:11, 9 June 2018 (UTC)[reply]
Thank you everybody for your tips and help. It is useful and would facilitate maintenance, so I'll follow your tips for sure, all the more as the template is still at first stage. My wonder is that it sometime happens an airport can have only one ICAO or one IATA code. What to do when nil? Example for Canala Airport which ICAO is NWWX ==>
{ '', 'NWWX', 'Canala airport', 'Canala' } ?--Bouzinac (talk) 16:46, 9 June 2018 (UTC)[reply]
You might modify RexxS's code so that it looks like this:
p.IATA = {}
p.ICAO = {}
p.WikiName = {}
for k, v in ipairs(p.codetbl) do
	if '' ~= v[1] then		-- if iata code is defined for this airport
		p.IATA[v[1]] = v[3]
		p.WikiName[v[1]] = v[4]
	end
	if '' ~= v[2] then		-- if icao code is defined for this airport
		p.ICAO[v[2]] = v[3]
		p.WikiName[v[2]] = v[4]
	end
end
Trappist the monk (talk) 17:10, 9 June 2018 (UTC)[reply]
Thank you gentlemen! I'll work it out sooner or later :) --Bouzinac (talk) 20:27, 9 June 2018 (UTC)[reply]
Ok, I've given some tries at {{#invoke:IATA and ICAO code/sandbox‎|function}} and Lua still not behaving as expected with data in sandbox being
 { 'AAA', 'NTGA', 'Anaa Airport', 'Anaa' }
. Any clue? Thank you again, folks. --Bouzinac (talk) 13:50, 10 June 2018 (UTC)[reply]
Have a look at Module:IATA and ICAO code/data/sandbox1 - note that the data module internally constructs all of the auxiliary arrays p.IATA, p.ICAO and p.WikiName which are exported to the module that uses them. That means that they are constructed once per page load and are then available in as many modules or functions you want to use them in. I think that Module:IATA and ICAO code/data/sandbox on line 3 has 'WikiName' and 'airportCityName' transposed compared with what you wrote at Module:IATA and ICAO code/data.
I've constructed a few example functions in Module:IATA and ICAO code/sandbox1. As you can see, the name values are immediately accessible via the IATA or ICAO code as an index to the respective table/array, which is accessed as part of the table you use to import the data - you called it master. So master.IATA["LSS"] contains "Les Saintes Airport" for example. I've done a few tests for you to look at at Module talk:IATA and ICAO code/sandbox1. Hopefully that will give you a start in whatever functionality you want to create. Cheers --RexxS (talk) 17:16, 10 June 2018 (UTC)[reply]
Thank you everybody and a coffee for Trappist the monk (talk · contribs) ! I think we're it. I'll put the sandbox code into primary code. Then further tests and parameters and data and then we might tell the template/module are functioning and usable. Un grand merci, again ! Bouzinac (talk) 18:55, 10 June 2018 (UTC)[reply]
The question that I asked but apparently not well enough, is: can the iata and icao airport names ever be different? You answered the question I didn't ask about the length of the iata and icao codes. Also, before you rush off to make this code live, I added a couple of TODOs: what should the table assembly code do when it encounters empty-string iata or icao codes in the tables in master? I think that nil or empty string values should be skipped.
Trappist the monk (talk) 19:20, 10 June 2018 (UTC)[reply]
An IATA code will ever be different from an ICAO code, for the very reason they do not have the same length (3 positions versus 4 positions). And to my mind, these codes should always refer to an airport (hence the link to the wiki airport page). Sometimes, you might have an old IATA code referring to an old airport and a new one. Ex : NKC nowadays ==> Nouakchott–Oumtounsy International Airport and before ==> Nouakchott International Airport, now closed. It is obvious only current and valid codes are to be shown. Nevertheless, an airport might happen to have only IATA code and not ICAO (and vice versa). Say : Canala airport, only NWWX and Kourou airport, only QKR. Did I reply to your interrogation? I'll look at your todo lists, so let's keep in sandbox for time being. Bouzinac (talk) 20:07, 10 June 2018 (UTC)[reply]
No, you did not. My question was about airport names can the name associated an iata code be different from the name associated with the 'equivalent' icoa code?
Trappist the monk (talk) 20:35, 10 June 2018 (UTC)[reply]
OK, get it. IATA and ICAO always refer to one airport, so same name result.--Bouzinac (talk) 20:39, 10 June 2018 (UTC)[reply]
Hello @Trappist the monk:, I've added an UPPER function. Are you content with the sandbox code scripting, may I put it into main code? Bouzinac (talk) 09:16, 11 June 2018 (UTC)[reply]
It occurs to me to wonder if some or all of the functions that Editor RexxS wrote in Module:IATA and ICAO code/sandbox1 should be included. Perhaps they'll be useful in future, perhaps not.
Trappist the monk (talk) 11:46, 11 June 2018 (UTC)[reply]
More things that occur to me:
  1. the function is called recode() but that doesn't seem like a very sensible function name to me; the name should either be specific to what the function does (it makes a wikilink) or very generic like main() – not a good choice if you elect to include Editor RexxS's functions.
  2. the data tables contain an airport name (IATA, ICAO) and a wkilink label (WikiName). The airport name is used as a wikilink target so the documentation in Module:IATA and ICAO code/sandbox should say that index[3] of the tables in master is the name of a wikipedia article about the airport. Similarly, index[4] is a the airport's city name used as a wikilink label. And this all leads me to suggest that perhaps renaming of the tables is in order, perhaps: IATAIATA_airport, ICAOICAO_airport, and WikiNamewikilink_label (and yeah, written this way because I find underscored names easier to read than CamelCase, especially as the the names get longer)
  3. if you are going to bold the erroneous code in one error message, not really necessary in my opinion, should you not do the same in others?
Trappist the monk (talk) 14:25, 11 June 2018 (UTC)[reply]
Not really, have you tried running it? It should not work because it has Lua code in Module:IATA and ICAO code/data/sandbox which is accessed via mw.loadData. I would use .. to concatenate strings rather than table.concat but I guess that's a style issue and doesn't matter. I would hope there is a more efficient way to look up information. At the moment the module loops over 600 items in a table to find what it needs. How many times would this module be used in one article? Roughly how many articles? Johnuniq (talk) 10:40, 11 June 2018 (UTC)[reply]
mw.loadData only cares about what they data module returns; it can compute that data any way it wants as long as it doesn't try to do things with frame objects. {{3x|p}}ery (talk) 11:28, 11 June 2018 (UTC)[reply]
(edit conflict)
I believe that you are mistaken (you know, it just astonishes the hell out of me to write that). See mw.loadData(), particularly these two bullet points:
  • The value returned from the loaded module must be a table. Other data types are not supported.
  • The returned table (and all subtables) may contain only booleans, numbers, strings, and other tables. Other data types, particularly functions, are not allowed.
As I understand it, there is nothing to restrict restrict how the returned table(s) is/are created, just a restriction that the module may only return tables.
The code in /data/sandbox is called once from /sandbox to create the three tables IATA, ICAO, and WikiName. Because this is an mw.loadData() call, the data tables are created only once per page rendering, not at every {{#invoke:IATA and ICAO code/sandbox}} in that page.
Yeah, .. v. table.concat() is a style choice, but since Lua is 'optimized' for table operations, I have taken to using table.concat except for very simple things.
Trappist the monk (talk) 11:39, 11 June 2018 (UTC)[reply]
Addendum: Yeah, the code does run, see Module:IATA and ICAO code/sandbox in the documentation transclusion.
Trappist the monk (talk) 11:46, 11 June 2018 (UTC)[reply]

Hello, so that everyone are aware, so far as I know, there is roughly ~12,000 ICAO and when known, ~5,600 IATA codes in the world. It would be specified in a wikipedia airport destination list table as many times as airports flown from this airport. I feel the sandbox module functionning very quick, but there are only France+USA codes in the sandbox data. Would the performance still good with 12000 lines in data ? Thanks again, Bouzinac (talk) 13:52, 11 June 2018 (UTC)[reply]

As a guess, probably not an issue. The {{lang}} and {{lang-??}} templates use several individual data modules, seven of which are massaged in one way or another in the mw.loadData (Module:Language/name/data) call. These several modules add up to about 16k lines. In a blank sandbox page I previewed these and took the results from the parser profiling data (drop-down at the bottom of the previewed page):
{{lang|es|casa}} – 8.78 MB/50 MB, 0.108/10.000 seconds
{{#invoke:IATA and ICAO code/sandbox|recode|AAA}} – 1.04 MB/50 MB, 0.010/10.000 seconds
Trappist the monk (talk) 14:50, 11 June 2018 (UTC)[reply]
I thank RexxS (talk · contribs) for his proposals but I don't think it is useful to have functions that would ask ""Paris - Charles de Gaulle"" returning result "CDG" (or LPFG). The only use case is to ask "CDG"===>wikilink+name or "LPFG"===>wikilink+name. However, an interesting function would be a module using sparql that would ask wikidata which airport wikilink has CDG as IATA airport code property... Are we set for move from sandbox to daylight? Thanks! Bouzinac (talk) 21:42, 11 June 2018 (UTC)[reply]
@Bouzinac: I think you'll find that sparql queries don't run in modules at the moment. You'll also find it is horribly inefficient to search through Wikidata for matching values, especially when you have key-value pairs that won't change very much over many years, and particularly given the fears of vandalism which might occur on Wikidata. In these sort of cases a look-up table is more controllable and efficient, and you have the right solution already. Obviously you could easily generate tables that were indexed by name and had the code as the value (reverse lookup), as easily as I generated the tables that lookup the name from the code. I'm not suggesting an immediate application for that sort of functionality, but it's worth you knowing that it's available, should someone require it in the future. --RexxS (talk) 22:38, 11 June 2018 (UTC)[reply]

@Pppery and Trappist: Thanks for the correction above, I was bitten by mw.loadData years ago but did not learn that detail which makes sense. It is counter-intuitive because a key design concept for Scribunto is that it should be possible to translate the wikitext at one point of a page to rendered output without any knowledge of any other wikitext on the page (there is no context). I wonder if the first call to a module that uses mw.loadData could pass a parameter that caused it to change the returned data. A second call would get mw's cache of the data and would therefore have context information from the first call. Johnuniq (talk) 00:04, 12 June 2018 (UTC)[reply]

On reflection, I can't think of a way to pass context other than what is globally obvious and fixed, such as the page title. I was wondering if an infobox could load a module and tell it key facts from the infobox, but it appears that it can't. Johnuniq (talk) 00:47, 12 June 2018 (UTC)[reply]

Reworked

@Bouzinac: I put a new version of the code in the sandbox (Module:IATA and ICAO code/sandbox + Module:IATA and ICAO code/data/sandbox). With this arrangement, the data is ready for use without the need for code to rearrange it. I guess it doesn't matter because the original version is very fast, but the new version is more efficient!

I noticed the following issues while extracting the data:

  • IATA duplicate codes: AAA, BOD, BVE, XCR.
  • Kourou has no IATA and no ICAO.
  • Ouanary has no IATA and no ICAO.
  • Assumed LSZM and LFSB are alternate ICAO codes for EAP.

Examples:

  • {{#invoke:IATA and ICAO code|main|LSZM}}Script error: No such module "IATA and ICAO code".
  • {{#invoke:IATA and ICAO code/sandbox|main|LSZM}}Script error: No such module "IATA and ICAO code/sandbox".

Johnuniq (talk) 10:12, 12 June 2018 (UTC)[reply]

@Johnuniq Thank you for your re-work of the function. However I don't find the data be easy to maintain:I'd rather prefer a data table looking like { 'AAA', 'NTGA', 'Anaa Airport', 'Anaa' } : every info is on a single line, easy to sort, edit and check in an excel sheet, so that everyone can maintain it.
  • You pointed out duplicate codes: so I'd would put a warning somewhere in the doc like "warning, there are twice AAA codes in data // There are twice "Kourou airport" in data //etc ". Is this possible to read the data and express some warnings when duplicates or lacks of airport wikipage name ?
  • Kourou has {'QKR', '','Kourou Airport','Kourou'} (no ICAO code). There is other wrong line of data, indeed.
  • EAP airport is specific because it has two ICAO code, based on the fact your airplane is bound to French side of Mulhouse airport == LFSB // bound to Swiss side == LSZM (France and Switzerland share the same airport building)
So the data (same building) {'EAP','LSZM, LFSB','EuroAirport Basel Mulhouse Freiburg','Basel, Freiburg im Breisgau, Mulhouse'},is wrong :), corrected. I'll work out code for Switzerland
Thank you again !Bouzinac (talk) 11:48, 12 June 2018 (UTC)[reply]
And I'm thinking to add the country, to help data be sorted and easy to be maintained. Bouzinac (talk) 11:49, 12 June 2018 (UTC)[reply]
The above tweaked per WP:LISTGAP.
Were it possible to get a data dump from the 'official' sources that could be massaged programmatically into the format suggested by Editor Johnuniq, a form that human editors didn't need to maintain, then that format should be preferred. But, I agree with Editor Bouzinac, that the single line, four member table, is more easily maintained by human editors who may be unfamiliar with Lua tables.
Trappist the monk (talk) 12:14, 12 June 2018 (UTC)[reply]
Just because I was curious, I repeated test I did before. The parser profiling data show:
{{#invoke:IATA and ICAO code/sandbox|recode|AAA}}
1.04 MB/50 MB, 0.010/10.000 seconds – tables built on-the-fly
1,009 KB/50 MB, 0.008/10.000 seconds – Johnuniq's static table
Trappist the monk (talk) 12:32, 12 June 2018 (UTC)[reply]
It's not fair that my code should be rewarded with such a pathetic performance boost! I tried to check a couple of others but it wasn't reasonable because currently the sandbox has old data while the main module has many more entries. I might play with it later, but I guess the take-home message is that there is a fair bit of overhead in Scribunto set up, and having Lua loop over a table a thousand times is comparatively minor. I couldn't do it because I remember when a floating point addition took a millisecond but it works. Johnuniq (talk) 07:15, 13 June 2018 (UTC)[reply]

Almost full data

Hello, I've build data from Wikidata. I might have to check for duplicates inside the data. How fares the quickness of the code? Bouzinac (talk) 22:34, 12 June 2018 (UTC)[reply]

There is an encoding problem with some of the country information:
Africa, République du Congo
Africa, République démocratique du Congo
Africa, Sainte-Hélène, Ascension et Tristan da Cunha
Asia, République populaire de Louhansk
South America, Saint-Christophe-et-Niévès
The way to check for duplicates and other detectable problems, and to have an easy-to-edit interface, is to enter the data as plain text in a specified format, and have a module which generates the data from that text. An extreme example of that is Module:Convert/data which is 100% generated from the input at Module:Convert/documentation/conversion data/doc. The current project does not need all that complexity but something a lot simpler could be devised.
The performance is fine as shown when previewing a couple of examples, although it is doing a lot of churning work. Johnuniq (talk) 01:22, 13 June 2018 (UTC)[reply]
I'm relieved with the performances being still fair. Is there a LUA function that I can copy-paste, so that the documentation of data renders a "human-readable" HTML sortable table with all data ? (or perhaps better to simply copy-paste inside Excel sheet). So that checking for duplicates+bad characters might be easy. Thanks again for this interesting project Bouzinac (talk) 07:02, 13 June 2018 (UTC)[reply]
My comment above was about checking during creation of the input data, but output of human-readable text is also possible with a bit of work. I've done that a couple of times, most recently at c:Module:Countries which has several data subpages. The show function displays all the data here using {{#invoke:Countries|show}}. You can copy/paste a table into Excel although Excel has an annoying habit of "fixing" your data so it cannot be relied on. In due course I may be able to help either on the input or the output side but probably not right now. Johnuniq (talk) 07:29, 13 June 2018 (UTC)[reply]
I have added a function to Module:IATA and ICAO code, duplicate_check() that scans the raw content of Module:IATA and ICAO code/data looking for improper iata and icao code lengths and for duplicates.
{{#invoke:IATA and ICAO code|duplicate_check}}
Script error: No such module "IATA and ICAO code".
The code is mostly untested but as you can see it found a duplicate of the DHN code.
Trappist the monk (talk) 12:29, 13 June 2018 (UTC)[reply]
That's nice because it has helped detect a problem in wikidata for 2 airports with DHN, corrected both in wikidata and data for the module... Thanks for this useful function, Trappist the monk (talk · contribs) ! Bouzinac (talk) 14:46, 13 June 2018 (UTC)[reply]

Multiples codes and automatic alphabetic sort

Hello, I might have another thing to ask you : let's suppose we code {{IATA and ICAO code|GRU|PEK|other codes etc}}, it would produce following result: Beijing–Capital, São Paulo–Guarulhos (Beijing being put alphabetical first, other airports sorted by alphabetical name). Would it be possible ? Bouzinac (talk) 09:34, 19 June 2018 (UTC)[reply]

I don't see why not. Instead of {{#invoke:IATA and ICAO code|main|{{{1}}}}}, write {{#invoke:IATA and ICAO code|main}}. In the module, take all inputs from the parent frame, process each code and store the results in a table, write a sort function to sort the results table according to the wikilink label, and output the result as a comma separated string.
Trappist the monk (talk) 11:05, 19 June 2018 (UTC)[reply]
I'll give it a try inside sandbox :) Bouzinac (talk) 11:37, 19 June 2018 (UTC)[reply]
Hi again, how is that you can have a "virtual" table filtered with frame.args, sort that virtual table, and export out wikilink labels comma separated ? Bouzinac (talk) 13:02, 20 June 2018 (UTC)[reply]

First, in the sandbox, start with a clean copy of the working live module using the live data set (we won't be changing that). I moved p.count(). Why is that function in the sandbox?

I created {{IATA and ICAO code/sandbox}} which invokes Module:IATA and ICAO code/sandbox but does not pass it any parameters. I then modifier the module sandbox to take the single argument from the parent frame. These should work correctly:

Trappist the monk (talk) 13:43, 20 June 2018 (UTC)[reply]

And support for multiple codes in pframe:
Trappist the monk (talk) 14:02, 20 June 2018 (UTC)[reply]
The above example should now be sorted.
Trappist the monk (talk) 14:18, 20 June 2018 (UTC)[reply]
(edit conflict) Seemed a good idea to remove duplicate wikilinks; in the above example, KORD and ORD are the same so one got removed from the final list.
Trappist the monk (talk) 15:12, 20 June 2018 (UTC)[reply]
I am in awe of such a simple and efficient code. Many thanks Trappist the monk (talk · contribs) !Bouzinac (talk) 15:09, 20 June 2018 (UTC)[reply]

Might be a job for Lua

 – Pointer to relevant discussion elsewhere.

Please see Template talk:Abbr#Link error detection; I'm not entirely sure about this one.  — SMcCandlish ¢ 😼  01:58, 13 June 2018 (UTC)[reply]

Does anyone know how {{Routemap}} could be made to run more efficiently without sacrificing functionality? The module caused Select Bus Service to exceed the template limits earlier this month. (Maybe the module could be split into subpages, although this would also have to be done on about 28 other wikis which also have the module.) Jc86035 (talk) 16:23, 16 June 2018 (UTC)[reply]

Viewing a permalink for 23:41, 31 May 2018 at that article, then viewing the parser report shows:
Post‐expand include size: 2097152/2097152 bytes
That means there was an attempt to transclude over 2MB of templates. That limit cannot be avoided (apart from substing some of the templates). No adjustment to the module can fix that problem. The only solution is to examine the output from each template (say in Special:ExpandTemplates) and decide whether there is any fluff that could be omitted without significantly impacting on the result. Johnuniq (talk) 01:27, 17 June 2018 (UTC)[reply]
It appears that 72.5% of the template output is inline CSS, based on {{East Coast Main Line diagram}}, so TemplateStyles should significantly take care of that. Jc86035 (talk) 07:48, 17 June 2018 (UTC)[reply]
Wow, that would be interesting. Please start planning! Johnuniq (talk) 08:10, 17 June 2018 (UTC)[reply]
@Johnuniq: I've created de:Modul:Routemap for testing (and also because {{BS-table}} really is overdue for a replacement over there). There's a lot that could be done just by looking at the source of a test diagram and copying all of the CSS; a lot of it is hardcoded into the table near the top which contains most of the table structure for input into string.format(). Jc86035 (talk) 08:45, 18 June 2018 (UTC)[reply]
Already about a 10% reduction in the size of the expanded wikitext. More to come some time later. Jc86035 (talk) 09:34, 18 June 2018 (UTC)[reply]
Non-rendered expansions during the processing of the page still count towards the limit and might be reduced without affecting the final result but I haven't examined the code. See Help:Template#Template limits. PrimeHunter (talk) 15:48, 17 June 2018 (UTC)[reply]
@PrimeHunter: I tested this partially with an empty transclusion of {{Routemap/sandbox}}. Deleting half of the text in Module:Routemap/sandbox had no effect on the post-expand include size, although maybe {{Rail-interchange}} (which needed a Lua conversion years ago) is also to blame. Jc86035 (talk) 18:24, 17 June 2018 (UTC)[reply]

Digit grouping example

It's not immediately obvious how to do this, and I've tried (probably incorrectly due to the lack of examples here) string.format & mw.language:formatNum, but couldn't get either to work 'out of the box'.   ~ Tom.Reding (talkdgaf)  00:29, 18 June 2018 (UTC)[reply]

These debug console statements seem to work for me:
=mw.language.getContentLanguage():formatNum (123456789.123) → 123,456,789.123
=mw.language.getContentLanguage():formatNum (123456789.123, {['noCommafy']=true}) → 123456789.123
Trappist the monk (talk) 00:44, 18 June 2018 (UTC)[reply]
Thank you Trappist. No wonder mw.language:formatNum( n ), as implicitly suggested in the MediaWiki doc, wasn't working... getContentLanguage() was the unintuitive (to me) bit missing. I'll try to make the instructions more clear.   ~ Tom.Reding (talkdgaf)  12:16, 18 June 2018 (UTC)[reply]
@Tom.Reding: It's difficult to make any progress with the weak documentation on MediaWiki. I had to use trial-and-error to figure out that the globalSiteId corresponding to the "be-tarask" code is actually "be_x_oldwiki", and I really think it's time we created our own resource by making pages here that contain useful examples for those calls. The way formatNum works is as a method on a language object, so if you already have a language object available for the language you want to use to format a number, you can write myLangObject:formatNum( number, options ). If you are working on enwiki, which is a monolingual wiki, then mw.language.getContentLanguage() will give you a language object for English. if you're interested in other language formats as well, there's an example call in Module:WikidataIB:
  • {{#invoke:WikidataIB |formatNumber | 123456780.123}} → 123,456,780.123
  • {{#invoke:WikidataIB |formatNumber | 123456780.123 |lang=de}} → 123.456.780,123
  • {{#invoke:WikidataIB |formatNumber | 123456780.123 |lang=hi}} → १२,३४,५६,७८०.१२३
Anybody else interested in creating examples here on enwiki? --RexxS (talk) 21:39, 18 June 2018 (UTC)[reply]

Idea

Would it be a good idea to create a "For every numbered parameter, do X" with X being specified as a parameter to the module (aka an extension of Module:For nowiki, except directly invoked)? This seems like it would obsolete a lot of pre-existing lua modules and make it easier to make templates not have arbitrary limits. {{3x|p}}ery (talk) 01:47, 29 June 2018 (UTC)[reply]

@Pppery: Isn't this basically Module:Separated entries? Jc86035 (talk) 02:07, 29 June 2018 (UTC)[reply]
No, because that modules returns output, whereas my proposed module expands Wikitext. To give an example, one could implement {{Anchor}}, which currently uses its own lua module, as {{#invoke:NAME|NAME|<nowiki>{{#tag:span|id={{{1}}}}}</nowiki>}}. (NAME, of course, would be replaced with the proper module name) {{3x|p}}ery (talk) 02:10, 29 June 2018 (UTC)[reply]
@Pppery: I think this is a good idea, although maybe you could work it into the existing module (maybe in a template function). Jc86035 (talk) 02:31, 29 June 2018 (UTC)[reply]
Which module is "the existing module" (Module:Separated entries, Module:For nowiki, or something else)?. {{3x|p}}ery (talk) 02:32, 29 June 2018 (UTC)[reply]
@Pppery: Sorry, I meant Module:For nowiki. Jc86035 (talk) 04:10, 29 June 2018 (UTC)[reply]
I like the idea of the intended results, however it gets done.  — SMcCandlish ¢ 😼  02:54, 29 June 2018 (UTC)[reply]
There's some chatter on a task related to TemplateData (phab:T54582) that maybe the "infinite parameter" pattern might be an anti-pattern. I'll leave that for others to think about. --Izno (talk) 03:45, 29 June 2018 (UTC)[reply]
It's more "there was some chatter 4–5 years ago". As for the proposal here, I note that passing wikitext through frame:preprocess() will likely be slower than processing data more specifically and avoiding that. Anomie 12:31, 29 June 2018 (UTC)[reply]
Has that thinking changed and no-one has commented to that effect on the task? (I personally am interested in TemplateData supporting infinite parameters, but that doesn't drive task consensus or implementation. :) --Izno (talk) 12:52, 29 June 2018 (UTC)[reply]
It's not clear how much that thinking was established in the first place. And letting people continue to proliferate it for 4 years doesn't help the case. Anomie 13:01, 29 June 2018 (UTC)[reply]
@Izno and Anomie: I personally prefer {{hlist}} (unlimited parameters) to {{flatlist}} (div wrapper) purely because it doesn't take up so much vertical space in the wikitext editor. I was aware this sort of thing created TemplateData issues but I didn't think anyone would actually care about it. Since Pppery's proposed module function would mainly be replacing other modules which already contribute to this anti-pattern, T54582 is probably not much of a concern here. Jc86035 (talk) 21:41, 29 June 2018 (UTC)[reply]
this idea (or rather, and extended version of it) was implemented in hewiki in he:Module:תבנית חוזרת. instead of "doing something" with every numerical (unnamed) parameter, you give it a prefix, say, "game_". the module then will collect all parameters of the form game_1, game_2, game_77, and apply some common behavior - most likely pass their value to some other template (also passed as parameter to this module). it was written by User:ערן - he may want to expand, and maybe correct any error i made describing the module. i'm not sure if the module supports "naked" prefix, which will do what the OP suggested, but even if it doesn't, it should not be that hard to teach it to perform this trick. the whole module is some 50 lines long, so it should not be that hard to read, understand, and modify if you want to spin your own derivative. peace - קיפודנחש (aka kipod) (talk) 05:49, 30 June 2018 (UTC)[reply]
That's how Module:Release timeline does it. Module:Citation/CS1 does it quite a bit differently. --Izno (talk) 14:29, 30 June 2018 (UTC)[reply]
@Izno, קיפודנחש, Anomie, Jc86035, and SMcCandlish: I believe I've implemented this in Module:For nowiki/sandbox, and converted Template:Anchor/sandbox to wikitext as a trivial example. What do you think? {{3x|p}}ery (talk) 16:51, 17 July 2018 (UTC)[reply]
@Pppery: I think this could be very useful, although for {{Anchor/sandbox}} maybe a standard span tag might be better than using the parser function. Jc86035 (talk) 17:13, 17 July 2018 (UTC)[reply]
I wasn't able to get that to work, since the <nowiki>...</nowiki> tags were escaping the < and > in the code. Perhaps I need to borrow some code from Module:Demo to handle that. {{3x|p}}ery (talk) 17:14, 17 July 2018 (UTC)[reply]

nitpick: your doLoop func looks like so:

local function doLoop(frame, args, code, sep, offset, argstosub)
	local result = ""
	code = mw.text.unstripNoWiki(code)
	for i, value in ipairs(args) do
		if i > offset + 1 then
			result = result .. sep
		end
		if i > offset then
			argstosub["i"] = i - offset
			argstosub["1"] = value
			local actualCode = code:gsub("{{{([^{}|]*)|?[^{}]*}}}", argstosub)
			result = result .. frame:preprocess(actualCode)
		end
	end
	return result
end

this means you call frame:preprocess() N times, concatenating the result. this is bad form: you want to minimize concatenation, and even more, you want to minimize calls to preprocess. it would be better to prepare everything, and call preprocess once:

-- this outline gets rid of "offset" (just b/c i did not understand what you are trying to do with it... - does not mean it should not be there)
local function doLoop(frame, args, code, sep, argstosub)
	local result = {}
	code = mw.text.unstripNoWiki(code)
	for _, value in ipairs(args) do
		table.insert(result, code:gsub("{{{([^{}|]*)|?[^{}]*}}}", value)) -- collect <whatever> in "result" table
	end
	return frame:preprocess(table.concat(result, sep)) -- call preprocess only once, at the end; use table.concat() instead of concatenating yourself
end

note that this is just an outline, not pretending to be correct, and completely botches the notion of "offset" (which i do not understand). i guess if you want to use this mode, you'll have to inject it back somewhere. my main point is, there's no advantage to calling "preprocess" separately for each item - build the whole !@#$%^ thing, and call preprocess() once, for the whole lot. peace - קיפודנחש (aka kipod) (talk) 17:43, 17 July 2018 (UTC)[reply]

Calling preprocess multiple times actually seems better to me, because it syncs better with Module:For loop, and because it isolates each input from the next one, which makes semantically more sense. In any case, all of that code was inherited from Petr Matas, who must have thought there was some reason to do it that way rather than concatenating the code. {{3x|p}}ery (talk) 17:57, 17 July 2018 (UTC)[reply]
Yes, I had isolation of inputs on mind. Note that in ordinary template transclusion a template is expanded in isolation as well. I would expect the cost of the preprocess() call to be comparable to the template tranclusion, which would be fine for me, but it is just a guess. Concatenating before preprocess() is a possible optimization, but are the potential problems worth it? Petr Matas 18:56, 17 July 2018 (UTC)[reply]
it is very much possible my comment was misdirected. the source of it was the explanation of preprocess() in the documentation (mw:Extension:Scribunto/Lua reference manual#frame:preprocess): it says something like

This expands wikitext in the context of the frame, i.e. templates, parser functions, and parameters such as {{{1}}} are expanded. Certain special tags ....(skipping)


...If you are expanding a single template, use frame:expandTemplate() instead of trying to construct a wikitext string to pass to this method. It's faster and less prone to error if the arguments contain pipe characters or other wikimarkup.


If you are expanding a single parser function, use frame:callParserFunction() for the same reasons.

to me, it reads: preprocess() is for processing large and ugly chunks of wikitext (and is not cheap, relatively speaking). with this in mind, my understanding is that it's better to call it once, with the whole enchilada, rather than inside the loop. if one cares about "isolation" and cleanliness, one should probably resort to frame:expandTemplate(). peace - קיפודנחש (aka kipod) (talk) 20:09, 17 July 2018 (UTC)[reply]
No template exists to be expanded in this case. {{3x|p}}ery (talk) 23:30, 17 July 2018 (UTC)[reply]

Ok, I've synced the sandbox of Module:For nowiki, so this is now live.
And here comes the end of many modules!
{{3x|p}}ery (talk) 23:30, 17 July 2018 (UTC)[reply]

I wonder how many of the ~1000 modules (excluding /data, /doc, /sandbox, /testcases, Module:Sandbox, and a few examples of modules whose subpages don't follow that format) can be replaced by this. {{3x|p}}ery (talk) 03:36, 18 July 2018 (UTC)[reply]

Preserving whitespace in submitted parameter value

What's the best way to have this input:

{{tag|!--|content= comment }}

output as (with the whitespace):

<!-- comment -->

instead of killing the whitespace and doing:

<!--comment-->

as is presently the case?

Yes, I know, we can do:

{{tag|!--|content=&nbsp;comment&nbsp;}}

but that's not the question.

My immediate guess would be that we already have a module capable of this, but that there's probably also an old-school way to do it, too. My fear is that leading/trailing whitespace is killed by the parser upon transmission (instead of after receipt and initial processing and before re-output), i.e. that the desired output isn't possible without hard-coding spaces in the template, or in the input.  — SMcCandlish ¢ 😼  01:53, 4 July 2018 (UTC)[reply]

You could modify {{tag}}? Barring that, perhaps something like this:
{{#invoke:String|replace|source={{tag|!--|content=comment}}|pattern=&lt;!%-%-%s*(.-)%s*%-%-&gt;|replace=&lt;!--&#32;%1&#32;--&gt;|plain=false}}
<!-- comment -->
Trappist the monk (talk) 03:08, 4 July 2018 (UTC)[reply]
@Trappist the monk: I meant that {{tag}} should be able to tell the difference between {{tag|!--|content= comment }} and {{tag|!--|content=comment}} with output matching the input.  — SMcCandlish ¢ 😼  05:37, 4 July 2018 (UTC)[reply]
Re the parser, your fear is well founded because the value of any parameter set with = has leading and trailing whitespace removed. That applies to templates and modules. The traditional workaround is to use |content=&#32;comment&#32; for the input which generates something equivalent to a space before and after. To handle a variety of input you would need code such as that from Trappist. Johnuniq (talk) 03:32, 4 July 2018 (UTC)[reply]
Yeah, we can't do that hard-coding of the space in the template, because {{tag|!--|content=comment}} should produce <!--comment--> not <!-- comment -->.  — SMcCandlish ¢ 😼  05:37, 4 July 2018 (UTC)[reply]
Weirdly, {{tlx}} preserves some space. With {{tlx|abbr|foo|bar}} you get {{abbr|foo|bar}}, but with {{tlx|abbr |foo|bar}} you get {{abbr|foo|bar}}. But it doesn't work consistently on all the parameters: {{tlx| abbr | foo | bar }} gives {{abbr|foo|bar}}.  — SMcCandlish ¢ 😼  05:43, 4 July 2018 (UTC)[reply]
It is documented somewhere that numbered parameters (those without =) are not trimmed, whereas named parameters (those with =) are. I have done some experiments. Assuming numbered parameters | abc | def | ghi the results are:
({{{1}}}+{{{2}}}+{{{3}}}) → ( abc + def + ghi )
({{#if: abc | abc }}) → (abc)
({{#if:{{{1|}}}|{{{1}}}}}+{{#if:{{{2|}}}|{{{2}}}}}+{{#if:{{{3|}}}|{{{3}}}}}) → (abc+def+ghi)
({{#if:{{{1|}}}|&#124;{{{1}}}}}{{#if:{{{2|}}}|&#124;{{{2}}}}}{{#if:{{{3|}}}|&#124;{{{3}}}}}) → (| abc| def| ghi)
That is, #if is doing something funky and inconsistent with spaces. I didn't bother setting up a reproducible experiment but if one were available the next step would be WP:VPT. Johnuniq (talk) 07:57, 4 July 2018 (UTC)[reply]
{{if}} exists to preserve that whitespace. {{3x|p}}ery (talk) 12:09, 4 July 2018 (UTC)[reply]
#if removes (trims) outer spaces for all parameters (named and unnamed), and consistently so. {{Trim}}} uses this feature.
Demo lines 2 and 3 by Johnuniq above show this effect. Line 4 still has the prefixed space, because by the addition of a character (&#124;), the prefixed space has become an internal space and so is not affected by trimming.
{{tlx}} shows spaces with parameter 1 only because that is the only parameter not #if-ed in code.
This saves us in situations with #ifeq, because the logic should not depend on spaces added in code:
{{#ifeq: {{{1|}}} |{{{1|}}}|a|b}} best be equal to {{#ifeq:{{{1|}}}|{{{1|}}}|a|b}}. -DePiep (talk) 11:58, 8 July 2018 (UTC)[reply]
Thanks, I was confused but see now that it is consistent. Johnuniq (talk) 22:52, 8 July 2018 (UTC)[reply]

Can't get require() working

In Module:track gauge/sandbox I want to add Module:Preview warning, but I can't get it working. Can someone take a look? The preview message should appear in this situation in preview:

9999 mm

-DePiep (talk) 11:35, 8 July 2018 (UTC)[reply]

This has nothing to do with require, but rather with Module:Preview warning (sidenote: which I've just nominated for deletion as unnecessary module forking), which is coded to only accept a frame, rather than a string. {{3x|p}}ery (talk) 11:51, 8 July 2018 (UTC)[reply]
I said "require" to indicate it is an internal module call, not an #invoke. Anyway, I see the original code Module:If preview also needs a frame not an argument. Is there a workaround for this? - DePiep (talk) 12:06, 8 July 2018 (UTC)[reply]
Solved. (Hardcoded module core code). - DePiep (talk) 12:23, 8 July 2018 (UTC)[reply]
@DePiep: In general, a solution can usually be constructed by writing the desired code to be a local ("private") function, something like:
  • local _myfunc = function( param1, param2 )
and then creating a "public" function which acts as a wrapper to the local function:
  • p.myfunc = function( frame )
  • return _myfunc( frame.args[1], frame.args[2] )
Obviously, you tailor the parameter(s} to what the call needs (or pass the entire table of frame.args). That allows you to include the module code in another module without having to use a frame object to call it. --RexxS (talk) 14:42, 8 July 2018 (UTC)[reply]
I see, will use this a next time. thx. - DePiep (talk) 14:56, 8 July 2018 (UTC)[reply]
not sure what user:RexxS meant when discussing "public" and "private" functions, so allow me to clarify:
modules can export functions to be used by templates. such functions take a single argument of type "frame", and by convention is also called "frame", and return a string. modules can also export any other function, to be used by other modules. such functions can take any number of parameters, of any type, including scalars, tables, and functions. the same module can export both types, e.g., Module:String exports template function "replace", used by calling {{#invoke:String|replace| .. parameters}}, and it also exports _escapePattern(), to be consumed by other modules, as in
local escaped = require('Module:String')._escapePattern(unescaped_string)
-- or, if you want to use it multiple times, like so:
local str = require('Module:String')
local escaped = str._escapePattern(unescaped_string)
so, in essence, both replace() and _escapePattern() are "public", but it's a different type of public... (granted, even the "template" functions can be called by other modules, but this is usually not a good practice, except the case where the caller simply passes the "frame" received from a "real" template)
peace - קיפודנחש (aka kipod) (talk) 19:34, 12 July 2018 (UTC)[reply]
Sorry if I was unclear. The idea of "public" and "private" functions became important concepts for object-oriented programming, where code would make certain functions available externally ("public") and others would not be accessible from external code ("private"). Those concepts were commonly used in languages like C++ and Java. In Scribunto, as kipod says, a Lua module can return a table (often called p) of functions that are available to the #invoke: call. Whereas require() effectively transcludes an entire module, so all of its code becomes available to the calling module. I tend to think of those functions available to the #invoke: as "public" and all of ones that are not as "private". Of course, there are lots of ways of looking at programming, so I apologise if my mindset introduced any confusion. --RexxS (talk) 22:31, 12 July 2018 (UTC)[reply]
@RexxS: - you were not "unclear" - you are simply wrong. in scribuntu, after calling x = require('Module:MyModule') the value of x is _exactly_ whatever the module returns, which by convention, is a single table (which in enwiki is usually called "p"). none of the functions in the module which are not explicitly returned are accessible to the requirer. peace - קיפודנחש (aka kipod) (talk) 23:21, 17 July 2018 (UTC)[reply]
Unless they're global. {{3x|p}}ery (talk) 23:23, 17 July 2018 (UTC)[reply]
@קיפודנחש: Sorry, but your understanding or reading of what I wrote is not correct. You can see the differences in documentation of 'require' between Scribunto and Lua 5.1: mw:Extension:Scribunto/Lua_reference_manual#require and http://www.lua.org/manual/5.1/manual.html#pdf-require - it's interesting to observe what is meant by "Loads the specified module." Unless something odd happens, you will find that all of the code in the loaded module is available (but not directly accessible) to the calling module. You are correct that the module's local functions are not directly callable from the calling module, but their code is available to all of the exported functions that makes use of them. Look at the example I gave above.
[Edit]: Okay, I can see where I was misleading you. Yes, you still have to have a "wrapper" like p._myfunc = function( param1, param2 ) to export a non-frame version of the local function. --RexxS (talk) 23:54, 17 July 2018 (UTC)[reply]
@RexxS: you were not "misleading me" - you simply made some wrong statements. in scribuntu (which, i guess is different than standard lua, and definitely different than many other frameworks such as node, go, php, .net etc.), you can't simply require a module and then access it's functions. here is the execrpt from the documentation explaining this:

Note that every required module is loaded in its own sandboxed environment, so it cannot export global variables as is sometimes done in Lua 5.1. Instead, everything that the module wishes to export should be included in the table returned by the module.

as i tried to explain above. (@Pppery: - as you can see, there is no such thing as "globals" your module can export. it can only export a single table, that's returned both to #invoke and to require().) peace - קיפודנחש (aka kipod) (talk) 16:05, 18 July 2018 (UTC)[reply]
I'm not sure if you're being deliberately obtuse, or just don't understand English. The original question was effectively "how do I make use of a public function that takes a frame as its argument?" The answer I gave was to rewrite the function as a local function with non-frame arguments and use a public function as a wrapper to call the local function. That makes the code (not the call) of the local function available to the external call. Which part of that don't you understand? I can see that only giving an example that exported a public frame-based function (for #invoke) could have been supplemented by a near identical example of exporting a public non-frame-based function (for use in another module), but I guess I assumed that most folks reading here would be smart enough to figure that one out for themselves. Perhaps I was wrong. --RexxS (talk) 16:37, 18 July 2018 (UTC)[reply]
you can call me names, and question my ability to understand english - i don't mind.
you wrote

require() effectively transcludes an entire module, so all of its code becomes available to the calling module.

this is simply wrong (it may be correct in "standard" lua, but is wrong in scribuntu). all the code of the required module is not available to the calling module - the only thing available is the single table returned by the required module. i understand you have difficulty admitting to a simple mistake - this is not a unique trait, and very common amongst humans. קיפודנחש (aka kipod) (talk) 21:00, 18 July 2018 (UTC)[reply]
That's nonsense. You just don't seem to understand how require works in Scribuntu. I did indeed write "require() effectively transcludes an entire module, so all of its code becomes available to the calling module" and that is correct no matter how many times you deny it. I can simply demonstrate the accuracy of what I wrote. Look at Module:WikidataIB/sandbox. There's a piece of code at lines 202-254 that takes a date and applies the users' preferences for dmy/mdy and bc/bce, returning a string. That's a local function called "format_Date". At lines 1367-1378 there are two public wrapper functions, one to allow #invoke access to the code, and the other to allow another module access to the code. When the module is loaded via require(), all of the code in the local function between lines 202-254 is available to any calling module through the wrapper function _formatDate(datetime, dateformat, bc). When the module is #invoked, all of the code in the local function between lines 202-254 is available to any page via the wrapper function formatDate(frame). Anybody can verify the truth of that, and that's what I described in my original reply above. Think about it this way: when a module is loaded through require, its entire code is loaded as if it were a "class" within the calling module, so the scope of any private objects inside that class is solely within that class, but public methods exposed by the class can be used to make all of the code inside it available. The technique I describe works, and I can use it to make any part of the code in any module available, so I can't see how you get the notion that it's somehow "wrong". --RexxS (talk) 22:26, 18 July 2018 (UTC)[reply]

I don't know what the manual's "cannot export global variables" refers to. While it is very bad idea to use globals, they do in fact work as can be seen in a test I just set up: main + required + results. Johnuniq (talk) 01:02, 19 July 2018 (UTC)[reply]

let me explain what "can't export" means: your required contains 2 functions. "square" and "cube". it returns a table that contains cube. anything in the returned table is available to the requirer, and anything else isn't, so your main() can use r.cube(). what RexxS wrote above is that requiring the module is akin to "transcluding" it, and all the functions in "temp" (including square() ) are available to the caller. i think RexxS thinks that in order for a function to be available it needs some kind of "wrapper" magic, which is plain silly. his sandbox contains the following superstitious segment:
p._formatDate = function(datetime, dateformat, bc)
	return format_Date(datetime, dateformat, bc)
end
there is no "wrapper" magic, and the above code is just silly. all you need in order to make format_Date() available to the requirer, is to add it to the returned table, like so: p._formatDate = format_Date. it is possible he does not fully comprehend how require works in scribunto: calling require() by itself (i.e., without assigning or using the return value) has zero effect. the return value of require() is exactly the value of the table returned by the module. this table can contain functions, scalars, other tables, and whatever you wish. nothing in the required module except the returned table is exposed to the reuirer. there is no "wrapper" magic - only the returned table. talking about "classes", "private", "public" is just confusing yourself with metaphors that do not belong to scribuntu. it is very simple: when you call require(), it returns exactly one table - the one returned by the module (which someone in enwiki decided needs to be called "p").
as a side, i personally think this pattern used in enwiki (creating an empty table at the beginning of the module, and accumulation values to it throughout the module, and at the bottom writing "return p"), is bad, and make it less clear and less readable. it is better to use the pattern (as in Module:Sandbox/Johnuniq/temp) of returning, at the end of the module, an explicit and anonymous table, that lists exactly what the module returns/exposes. for instance, the module RexxS linked to, Module:WikidataIB/sandbox, exports dozen or more functions, but it's a pain in the ass to figure out which, exactly. it would be better if there was no "p", and the statement at the end of the module, instead of "return p", would read:
   return {
-- list anyting you want to return here, e.g.
   _formatDate = formatDate,
-- or even
  ['any string'] = formatDate,
  anotherExportedFunction = someOtherFunction,
-- etc.
   }
this way the list of things returned by the module is clear and accessible. i cannot think of a single advantage to the pattern used in enwiki, but apparently some people think it's mandatory. peace - קיפודנחש (aka kipod) (talk) 06:55, 19 July 2018 (UTC)[reply]
"calling require() by itself ... has zero effect" We are being pedantic here so while that statement is correct in practice, it is not literally correct. Executing require would leave global variables/functions available for use in the requirer. Re your last point, while I agree, I have read strong opinions to the contrary that point out that while reading a module, seeing "local" in front of everything suggests that everything is local and the reader would find their expectations confounded by the export which turns some of the local functions into effectively global. Johnuniq (talk) 07:20, 19 July 2018 (UTC)[reply]
I see that kipod has changed his tune. It now seems that what I wrote wasn't wrong, but he just doesn't like how I write code. He calls it "silly", and then makes up what he thinks I'm thinking, just so that he can criticise it. Strawman. He apparently doesn't realise that his function assignment p._formatDate = format_Date and my explicit function declaration have exactly the same effect. The difference is that explicitly defining the function is much clearer for others to read than that sort of assignment. You use a wrapper here to make clear you are defining a public function; it's not "magic". Shortening code to the minimum is how script-kiddies write programs, making them as obscure as possible in the hope that only they can understand them. Module:WikidataIB actually has all of its local (private) functions defined in the first section (labelled "private functions") and all of the exported (public) functions in the second section (labelled "public functions"), so figuring out what is exported is just a matter of looking at that section, or reading the f***ing documentation.
Nevertheless, I do have a lot of sympathy with his suggestion of collecting all of the public functions at the end of the module and returning a table of functions to export there, but since that is not the style currently used on enwiki and in all of the examples for new programmers, I don't intend to complicate matters any further for new Lua editors by offering an alternative style. We have few enough new Lua editors without putting any of them off with multiple variations that all do the same job. --RexxS (talk) 13:16, 19 July 2018 (UTC)[reply]
this begins to get personal, so maybe it is not productive, but let me elaborate a little bit. what RexxS wrote above ("require is like transclusion") is wrong for scribuntu (while being correct for lua in general). i would not comment on the fact that the "wrapper" is useless and silly, except the fact that in his previous (wrong) comment, he said that such wrapper is actually _needed_ in order to export something (in his words: "Yes, you still have to have a "wrapper" like p._myfunc = function( param1, param2 ) to export a non-frame version of the local function").
but let's leave the personal stuff aside, and maybe we can clarify some stuff that became murky in the discussion.
some notes about difference between vanilla lua and scribuntu, locals, globals, and require()
so, in vanilla lua, require() does (almost) exactly what RexxS described above: it's like transcluding all the "global" stuff (functions and variables) from the required module:
"pure" lua
FILE a.lua
    var1 = 'hey'
    local var2 = 'ho'

function func1()
    return 'i ma here'
end

local func2() 
    return 'i am also here'
end
FILE b.lua
   ok = require('a') 
   print(ok) -- prints "true", indicating successful require
   print(var1) -- prints 'hey' to stdout
   print(var2) -- prints 'nil' - var2 is not known in module b - it is local to module a
   print( func1() ) -- prints "i ma here"
   print( func2() ) -- throws an error: in module b 'func2' is nil

in contrast, with scribuntu, things are different: if you use the same code (well, replace "print" with mw.log(), drop the .lua, and add "Module: to the require statement... ), the first difference is that "ok" will not be true, and instead will be nil: module "A" does not have a "return" statement. everything else will be nil too, since the required module is loaded in a sandbox. in order to get some value from our required module, we will need to explicitly return the stuff we want, in a table. so let's do this exercise:

scribuntu example
module a
    var1 = 'hey'  
    local var2 = 'ho'
    var3 = 'here'
    local var4 = 'there'

function func1()
    return 'i ma here'
end

local func2() 
    return 'i am also here'
end

return {
   v3 = var3,
   v4 = var4, -- expose var4 - the fact that it's declared "local" has no effect
   func2WithFancyName = func2, -- again, we expose func2 (as func2WithFancyName), regardless of the fact that it was declared "local"
   -- all the "global" things, variables or functions, which are not exported via this table are not accessible outside this module, so their "globality" is an illusion.
}
module b
   a = require('a') 
   -- here, a.v3 is 'here', a.v4 is 'there', and a.func2WithFancyName is a function which will return 'i am here'

so with scribuntu, "local" and "global" (or "private" and "public") are meaningless notions, when discussion require(), and have no effect on visibility (since everything is made "local" anyway, by the scribuntu framework). the only meaningful thing is the table that require() returns.

now, as Johnuniq pointed out, my statement above that calling "require()" by itself (i.e., without using the value returned by it) has zero effect, is not technically correct: when you call require(), in addition to consuming some memory for the module's code, all the "free" code (i.e. code outside of any function) in the module will execute. however, b/c of scribuntu's sandboxing, the only effect of such require, can be consumption of memory and cpu, and posting to the "scribuntu logs" by calling mw.log() and it's brethren (modulo bugs in scribuntu, of course). scribuntu guards against any other effect. peace - קיפודנחש (aka kipod) (talk) 16:54, 19 July 2018 (UTC)[reply]

You're quite right: I misspoke when I said you need a wrapper function. I should have said you need some means for a calling module to access the code that is loaded by require(), and a wrapper is not the only way to do that (although in the circumstances of the original post, it would be my preferred way, in order to keep a parallel with accessing the code via #invoke). --RexxS (talk) 17:33, 19 July 2018 (UTC)[reply]
I'm trying to understand what Scribunto "sandboxes". I always assumed that mention of Lua sandboxing was referring to code to ensure that a module could not do anything other than generate text to be used for the expansion of a #invoke. At any rate, I have modified my example: main + required + results. The results are the same as before but the required module does not return anything. Johnuniq (talk) 05:08, 20 July 2018 (UTC)[reply]

amazing. so it turns out i'm the one who does not understand how scribuntu's require() actually works. i always took the documentation (or rather, my understanding of the docs) at face value, and never bothered to actually test it. i owe an appology to RexxS then - sorry for insisting you were wrong when i was the one in error. i still suspect this may be a bug that crept into scribuntu at some point, but more likely, my faulty undersanding is the real bug... sorry for the confusion. maybe User:Anomie can explain what the sandboxing comment really means? should i go back to all the modules i wrote and make sure everything is local? peace - קיפודנחש (aka kipod) (talk) 16:30, 20 July 2018 (UTC)[reply]

There are two levels of sandboxing in Scribunto. The first removes various features that could be used to access the filesystem of the server or to affect other running processes. The second prevents the code from one {{#invoke:}} from affecting or communicating with code from a different {{#invoke:}} on the page.
As for the comment I'm removing from the reference manual in mw:Special:Diff/2833647, it looks like it was a bug which was fixed as part of T49300. Due to that bug, the globals were being loaded into the wrong scope which is why it seemed like it wasn't possible at the time. Anomie 16:56, 20 July 2018 (UTC)[reply]

Hi, I'm trying to write a module named Module:NYC bus link, which will replace Template:NYC bus link (and later, Template:LI bus link). Currently, the NYC bus link templates creates comma-separated lists of links to multiple NYC bus routes, linking to pages with suffixes of "(New York City bus)". This will work for NYC bus routes with various prefixes excluding "N", e.g. the code {{NYC bus link|M60|Q44}} will produce "M60, Q44". The LI bus link template does the same thing with suffixes of "(Long Island bus)". This will work for any NYC-area bus route with the prefix "N", e.g. the code {{LI bus link|N22|N22A}} will produce "N22, N22A". I have tried to put code in Module:Sandbox/Epicgenius/NYC bus link, but I don't know Lua.

However, both templates only allow up to 20 links. I want to extend that to an infinite number of links. Since I have never written a Lua template before, I was wondering if someone could give me advice on how I could write this module. Thanks in advance. epicgenius (talk) 21:48, 8 July 2018 (UTC)[reply]

Like this?
{{#invoke:Sandbox/Epicgenius/NYC bus link|getLink|city=NYC|M60|Q44}}
M60, Q44
{{#invoke:Sandbox/Epicgenius/NYC bus link|getLink|city=LI|N22|N22A}}
N22, N22A
Trappist the monk (talk) 22:17, 8 July 2018 (UTC)[reply]
@Trappist the monk: Yes, that's exactly what I was looking for. Thank you. epicgenius (talk) 22:19, 8 July 2018 (UTC)[reply]
The above is mindless; it should be improved to accept any case for |city=: nyC, Li, etc; it should be improved to do something sensible when given a nonsensical city abbreviation.
Trappist the monk (talk) 22:21, 8 July 2018 (UTC)[reply]
Definitely. I just needed this template to replace {{NYC bus link}} and {{LI bus link}} for the time being. More cities could be added if necessary. epicgenius (talk) 22:24, 8 July 2018 (UTC)[reply]

Date & Wikidata help

I wish to explore how Lua imports dates from Wikidata. I'm interested in testing edge cases, like hears at the edge of a century, years BC, and years with more than 4 digits. I have experience one Lua module and have a Lua textbook, but could use some help, so I don't have to find and wander through reams of Lua/Wikidata documentation for one simple task.

I want to put a date in the Wikidata Sandbox (Q4115189)‎. Then I want to view a page in my userspace and see the date that has been imported from Lua. I'd appreciate any help.

Also, in places like infoboxes, are dates usually used "raw", or are there certain functions that are usually used to make them look more palatable? Jc3s5h (talk) 20:36, 17 July 2018 (UTC)[reply]

@Jc3s5h: In Wikidata, data of type "time" are stored as timestamps that look like "+2018-07-17T00:00:00Z" along with a precision which can be from a day to a billion years. The year in the datestamp now has a minimum of 4 digits, but may have more. The month and day may be "00" if the precision means their value is not significant.
In Module:WikidataIB, which is intended for use in infoboxes, we also have to deal with preferences for "dmy" vs "mdy" and for "BC/AD" vs "BCE/CE", because different articles will use different preferences. The wikibase client offers a method mw.wikibase.entity:formatPropertyValues that returns a string that looks like "1 August 30 BCE" for the stored timestamp value "-0030-08-01T00:00:00Z". That doesn't cope with ranks, but might be useful at some point, so the code in WikidataIB first converts each timestamp into the recognisable dMy/BCE format, then passes that into a routine that deals with dmy/mdy and BC/BCE preferences. It doesn't presently cope with years that have more than four digits, but that's not difficult to patch with a regex. I've left it for now because every date with a 5 digit year that I've come across so far has been a typo, so I find it useful to flag up. YMMV.
If you're dealing with Wikidata, you'll need to cope with timestamps like "+1872-00-00T00:00:00Z", which is how the geniuses over there decided to store "1872 (precision year)". The standard libraries treat that as the day before 1872-01-01, which is 1871-12-31, so of course the year turns out wrong.
Please feel free to re-use as much of the code in that module as you find useful. I've tried to annotate as much of it as I could. Let me know if I can help any further. --RexxS (talk) 23:10, 17 July 2018 (UTC)[reply]
I think I need to look at a higher level view. For example, could I create a simple infobox in my user space, or are there presumptions in place that looks at the Wikidata item that corresponds to the article the infobox appears in, so maybe the extraction can be worked with is in an article that has a corresponding Wikidata item. If that obstacle does not exist, can you suggest a simple infobox with a date that I could instantiate in my user space? Jc3s5h (talk) 01:01, 18 July 2018 (UTC)[reply]
@Jc3s5h: Is this related to the issue with Wikibase storing "20th century" as 2000-00-00 by default? Jc86035 (talk) 07:01, 18 July 2018 (UTC)[reply]
There are a number of ways to store information into the Wikibase repository. There is the interactive user interface, a bot, Quickstatements, etc. The only one I personally have used is the interactive user interface. With that, you can enter the date in several formats, like January 1, 2050, then manually setting the precision to "century". Looking at the diff in a place like the Wikidata sandbox (QQ4115189) you see it stores whatever date you provided and whatever precision you provided. But if you entered, for example "January 1, 2100" the interactive user interface will display it as "21.century" when it really should be grouped with the other years in the 2100-2199 range.
I did some experimenting with the interactive user interface and found that I could enter "2100" with a precision of century and it would store it as "+2100-00-00T00:00:00Z" with precision 7. Jc3s5h (talk) 11:52, 18 July 2018 (UTC)[reply]
You are not limited to retrieving dates from within the linked article. Here are some date of birth (P569):
  • For Richard Burton (Q151973): {{#invoke:WikidataIB |getValue |P569 |qid=Q151973 |fwd=ALL |osd=no}} → 10 November 1925 Edit this on Wikidata
  • For Philip the Arab (Q1817): {{#invoke:WikidataIB |getValue |P569 |qid=Q1817 |fwd=ALL |osd=no}} → c. 204 Edit this on Wikidata
  • For Francesco Borromini (Q123150): {{#invoke:WikidataIB |getValue |P569 |qid=Q123150 |fwd=ALL |osd=no}} → 25 September 1599, 27 September 1599, 1599 Edit this on Wikidata
If you want to see how the data is actually stored on Wikidata:
table#1 {
    table#2 {
        ["id"] = "Q1817$FFB1F533-8501-4599-8FB3-E6256454B847",
        ["mainsnak"] = table#3 {
            ["datatype"] = "time",
            ["datavalue"] = table#4 {
                ["type"] = "time",
                ["value"] = table#5 {
                    ["after"] = 0,
                    ["before"] = 0,
                    ["calendarmodel"] = "http://www.wikidata.org/entity/Q1985786",
                    ["precision"] = 9,
                    ["time"] = "+0204-00-00T00:00:00Z",
                    ["timezone"] = 0,
                },
            },
            ["property"] = "P569",
            ["snaktype"] = "value",
        },
        ["qualifiers"] = table#6 {
            ["P1480"] = table#7 {
                table#8 {
                    ["datatype"] = "wikibase-item",
                    ["datavalue"] = table#9 {
                        ["type"] = "wikibase-entityid",
                        ["value"] = table#10 {
                            ["entity-type"] = "item",
                            ["id"] = "Q5727902",
                            ["numeric-id"] = 5727902,
                        },
                    },
                    ["hash"] = "cb40f2027a88b8d23735681aaccba1069a574f54",
                    ["property"] = "P1480",
                    ["snaktype"] = "value",
                },
            },
        },
        ["qualifiers-order"] = table#11 {
            "P1480",
        },
        ["rank"] = "normal",
        ["references"] = table#12 {
            table#13 {
                ["hash"] = "bbfc00cd1443559e385efbed4e9d5118cd6c7305",
                ["snaks"] = table#14 {
                    ["P1810"] = table#15 {
                        table#16 {
                            ["datatype"] = "string",
                            ["datavalue"] = table#17 {
                                ["type"] = "string",
                                ["value"] = "PHILIPPE L'ARABE MARCUS JULIUS PHILIPPUS",
                            },
                            ["property"] = "P1810",
                            ["snaktype"] = "value",
                        },
                    },
                    ["P248"] = table#18 {
                        table#19 {
                            ["datatype"] = "wikibase-item",
                            ["datavalue"] = table#20 {
                                ["type"] = "wikibase-entityid",
                                ["value"] = table#21 {
                                    ["entity-type"] = "item",
                                    ["id"] = "Q1340194",
                                    ["numeric-id"] = 1340194,
                                },
                            },
                            ["property"] = "P248",
                            ["snaktype"] = "value",
                        },
                    },
                    ["P3219"] = table#22 {
                        table#23 {
                            ["datatype"] = "external-id",
                            ["datavalue"] = table#24 {
                                ["type"] = "string",
                                ["value"] = "marcus-julius-philippus-philippe-l-arabe",
                            },
                            ["property"] = "P3219",
                            ["snaktype"] = "value",
                        },
                    },
                    ["P813"] = table#25 {
                        table#26 {
                            ["datatype"] = "time",
                            ["datavalue"] = table#27 {
                                ["type"] = "time",
                                ["value"] = table#28 {
                                    ["after"] = 0,
                                    ["before"] = 0,
                                    ["calendarmodel"] = "http://www.wikidata.org/entity/Q1985727",
                                    ["precision"] = 11,
                                    ["time"] = "+2017-10-09T00:00:00Z",
                                    ["timezone"] = 0,
                                },
                            },
                            ["property"] = "P813",
                            ["snaktype"] = "value",
                        },
                    },
                },
                ["snaks-order"] = table#29 {
                    "P248",
                    "P3219",
                    "P1810",
                    "P813",
                },
            },
        },
        ["type"] = "statement",
    },
}
Century years are controversial. Because there was no year zero, the First Century started in year 1 and hence ended in year 100; the Second Century from 101 to 200, and so on. The Second Millennium technically started on 1 January 2001 for the same reason. However some folks will disagree with that, so you can't please everyone. Either 2100 is the last year of the 21st Century, or the first year of the 22nd Century according to taste. --RexxS (talk) 13:09, 18 July 2018 (UTC)[reply]
Thanks very much; in the last several hours I've been trying to figure out how to use #invoke in an ordinary page rather than in a module (which was totally off-track) or a template. I'd figured out Wikidata, but not WikidataIB. I can get started without having to write any Lua myself. If we figure out what to do with some of the dates, I might want to try some sandbox changes to the WikidataIB code later on. Can you suggest how to set up a simple test environment?
As for the substance of your date questions, I need some time to digest it and some other stuff to do today. Jc3s5h (talk) 13:32, 18 July 2018 (UTC)[reply]
I keep "test cases" for WikidataIB in Module talk:WikidataIB/testing for want of a better place and the same tests for Module:WikidataIB/sandbox at Module talk:WikidataIB/sandbox/testing. They should be useful for seeing examples of what can be done with the module. Feel free to add more sections or use your own user space as a test environment. When you want to try amending code, there are at least three sandboxes: Module:WikidataIB/sandbox, Module:WikidataIB/sandbox1, and Module:WikidataIB/sandbox2. They are not used much lately, so you can experiment as much as you like in those without disturbing any articles (they may need to be synchronised with the main module by copy-paste). --RexxS (talk) 16:00, 18 July 2018 (UTC)[reply]

First Lua module review: sfnt

I just made some changes to Module:Footnotes/sandbox for to be used by the new Template:sfnt. I'm new to Lua and Scribuntu, so I was hoping a more experienced editor could review my work. I also have a couple specific questions:

  1. Rather than just stripping Talk from the page name via gsub, I'd like to use the equivalent of the magic word {{SUBJECTPAGENAME}}, but I don't see how to do this in Lua.
  2. The template currently emits an error via {{sfnt}} (as I want it to) when used in any non-talk namespace. Is it a best practice for this to be included in the Module (Module:Footnotes/sandbox), or in the Template ({{sfnt}})? If this should be done in the module, then I would welcome suggestions for sample modules with similar behavior.

Thanks! Daask (talk) 15:29, 23 July 2018 (UTC)[reply]

Whoops, it actually doesn't work. frame:getParent():getTitle() is always returning Template:sfnt rather than the page that {{sfnt}} is transcluded in. I'm not sure how to fix this. Daask (talk) 15:48, 23 July 2018 (UTC)[reply]
I think you want mw.title.getCurrentTitle().namespace to get the article namespace (see mw:Extension:Scribunto/Lua_reference_manual#mw.title.getCurrentTitle) There are other object there that may be handy.
Trappist the monk (talk) 16:01, 23 July 2018 (UTC)[reply]
@Trappist the monk: Thanks for the tip. It's working fine now. Do you have guidance on my second question, or other suggestions? Daask (talk) 19:34, 27 July 2018 (UTC)[reply]
Only this: put the {{#invoke:}} inside the {{#ifeq:}}
{{#ifeq:{{FULLPAGENAME}}|{{TALKPAGENAME}}|{{#invoke:Footnotes/sandbox|sfnt}}|{{error-small|{{tl|sfnt}} should only be used in [[Wikipedia:Namespace#Talk namespaces|Talk namespaces]].}}}}
Trappist the monk (talk) 11:31, 29 July 2018 (UTC)[reply]
It's also fine in "Wikipedia:" namespace. All the "talk" formatting templates are also used in noticeboards which function like talk pages in most respects.  — SMcCandlish ¢ 😼  21:45, 31 July 2018 (UTC)[reply]

Issue with test case / TemplateStyles

Does anyone know how modules treat TemplateStyles? {{Test case}} thought {{Adjacent stations/sandbox}} and {{Adjacent stations/sandbox2}}, with identical wikitext, were different, but when I removed the TemplateStyles tag on each of them the template said they were the same. Jc86035 (talk) 12:38, 24 July 2018 (UTC)[reply]

It's a strip marker issue, but Module:Template test case is supposed to handle strip markers with the TestCase:templateOutputIsEqual() function. Both of the transcluded pages below contain the same content. Jc86035 (talk) 10:12, 27 July 2018 (UTC)[reply]

Test cases
{{User:Jc86035/sandbox3}}

{{User:Jc86035/sandbox3}}

{{User:Jc86035/sandbox4}}

{{User:Jc86035/sandbox3|this displays a nowiki tag instead of the templatestyles tag}}

{{User:Jc86035/sandbox3}}

{{User:Jc86035/sandbox4}}

}}

Notifying Mr. Stradivarius, who wrote the function. Jc86035 (talk) 10:16, 27 July 2018 (UTC)[reply]

Never mind; this was because the strip marker format was changed in 2015. I've updated the module. Jc86035 (talk) 10:26, 27 July 2018 (UTC)[reply]

Request Lua module for removing/striping leading zeros

Hello there! I am not familiar with Lua, but I would like to invoke a module for Template:SEHK to remove all leading zeros. This is needed as the template uses the numerical stock code inputted and replaces the value inside the stock exchange URL. The problem is that SEHK tickers are often reported in the English media with leading zeros (making it up to 4 digits, such as "0001" rather than just "1") The current stock website does not support leading zeros, hence redirecting to an error site. I was wondering if anyone here experienced with Lua can help with this issue? It has been affecting a wide range of Hong Kong stock exchange-listed articles. Cheers –Wefk423 (talk) 18:49, 26 July 2018 (UTC)[reply]

It's easy enough to write a module to use the Lua function tonumber(), but it's probably simpler to use the magic word {{#expr: }}. For example, {{#expr:0001}} gives 1. HTH --RexxS (talk) 19:09, 26 July 2018 (UTC)[reply]
Expr seems really reasonable considering the other alternative of Module:String#Replace (finding regex 00+ and replacing with nothing). Template:Trim exists. Expr emits an NAN if the input is bad, no? --Izno (talk) 19:26, 26 July 2018 (UTC)[reply]
Thanks for the suggestion. I have added the magic word {{#expr: }} to the template to resolve the error webpage issue for now. But I do think that such module (with usage tutorial) can be created as other templates might also need to strip leading zeros. It seems like a fast and easy way, especially for users who don't know how to use magic words. –Wefk423 (talk) 19:35, 26 July 2018 (UTC)[reply]
(edit conflict) It throws an error for me: {{#expr:ABCD}}Expression error: Unrecognized word "abcd".
If you want to control the errors, then a Lua module starts to become attractive:
p = {}
p.stripzeros = function(frame)
	x = tonumber(frame.args[1])
	if x then
		return x
	else
		return "whatever you want to indicate NaN"
	end
end
return p
Usage: {{#invoke:Modulename |stripzeros |number-goes-here}}HTH. --RexxS (talk) 19:40, 26 July 2018 (UTC)[reply]
Thank you so much for the great suggestion on customizing the error message by using this Lua module. It is currently live at Module:Leading zeros and has also been implemented in Template:SEHK. Way much better than the red bold message which will look terrible in a infobox. When inputting a non-numeric value, it will now appear as "SEHK: Incorrect". How do you think? Cheers! –Wefk423 (talk) 00:21, 27 July 2018 (UTC)[reply]
@Wefk423: That seems to do the job for you. If you re-use the module in other applications, you can trap the error word "Incorrect" with an {{#ifeq: }} test in the template, which will allow you to take different actions when the input is not a number.
One other thing (in your documentation): I would encourage everyone not to use <br> to separate items in a list (see MOS:NOBR. Using {{ubl}}, especially in an infobox, is much better because it creates a real list that is much more useful for screen readers. Cheers --RexxS (talk) 09:33, 27 July 2018 (UTC)[reply]
@RexxS: I'm sorry I don't really catch that. Which documentation are you refering to? I don't seem to find any list. Nevermind, I found it! I've edited the documentation of the template here. Thanks and cheers –Wefk423 (talk) 16:32, 27 July 2018 (UTC)[reply]

Simplifying invocations of Lua modules when designing templates

One of the nuisances of designing infoboxes and similar templates that draw data from Wikidata is that we often want that value to appear only if it exists (or in other cases if it's not equal to a particular value). That usually involves making two calls to the Lua module to fetch the Wikidata – once to test it, and a second time to display its value. Using a "helper" template that takes the {{#invoke:}} as a parameter and uses that parameter twice is a possible work-around that simplifies the infobox (or other template) design. I've created two new templates Template:If then show and Template:Ifnoteq then show as illustrations of the technique, along with some simple documentation of they may be used. Hopefully they may prove useful. --RexxS (talk) 12:45, 27 July 2018 (UTC)[reply]

Convert Infobox Chinese/Chinese

Would someone mind converting Template:Infobox Chinese to Lua? It's so the order of the romanization options can be changed (such as displaying Cantonese first in the uncollapsed/expanded template when the subject is Hong Kong) - From Template_talk:Infobox_Chinese#Reversing_the_order_of_Mandarin,_Cantonese,_and_Hakka_in_the_case_of_Hong_Kong_and_Macau_articles?

@Kdm852: @Citobun:

Thanks WhisperToMe (talk) 13:56, 30 July 2018 (UTC)[reply]

(I asked WhisperToMe to post here since I probably don't have the time to deal with this.) There's also a section on the template's talk page about the merger with another template which is stalled because both templates are fairly complicated and presumably difficult to work with. This might require modification to Module:Infobox to allow modules to use it, or the new module could just generate its own table (which might be somewhat easier). Jc86035 (talk) 14:02, 30 July 2018 (UTC)[reply]

Improving Template:Code

I'm wondering if it's feasible to re-do {{code}}, a wrapper for <syntaxhighlight>, in such a way that some parameter, perhaps |filter=y, could pre-filter and convert some of the input before it reaches the underlying <syntaxhighlight> process. [Inserting a code snippet for example purposes below: <span>.]

  • The issue: Sometimes it is not desirable to feed this template something literal. E.g., if you do {{code|lang=html|1=<span style="color: purple;">}} (without the closing tag for the span), then anyone using the edit-mode wikimarkup syntax highlighter by Remember_the_dot, available at Special:Preferences#mw-prefsection-gadgets and thus our most frequently used highlighter, will have their syntax highlighting in the editing window boogered by what Remember_the_dot's syntax highlighter sees as a real open and not-yet-closed <span> rather than as template content. [If you use that highlighter, and are reading this in edit mode, you should see this effect now, caused by the snippet I inserted before this bullet list. Most of my entire post should have a pink background as unclosed code content when it really is not.]
    • And one cannot escape this with &lt; to encode the exmaple span's leading < symbol; all input received by <syntaxhighlight> is treated as a literal.
    • This also makes it impossible to do something like {{code|lang=html|1=<span '''style'''="color: purple;">}} to emphasize something in the markup.
  • The idea: Use Lua and a table of entities and of select wikimarkup to pre-filter (and possibly post-filter) the content before (and maybe after) it hits <syntaxhighlight>:
    • Pre-filter so that things like < can be escaped in the visible wikitext with &lt;, converted to <, then passed to the parser function.
    • Possibly also tokenize a few things like ''...'' and '''...''' markup so they can be operated on after the fact:
    • Post-filter to de-tokenize those bits and actually perform their intent. Ideally this would also include <var>...</var> so that variables within code can be marked up as such (lack of ability to do that is a serious flaw in <syntaxhighlight>).

 — SMcCandlish ¢ 😼  22:12, 1 August 2018 (UTC)[reply]

This is getting called a lot (2600+ times) by WP:CRAPWATCH/SETUP, so any help in making it more efficient would be appreciated, as well as scale to an infinite number of unnamed arguments. Headbomb {t · c · p · b} 16:46, 13 August 2018 (UTC)[reply]

Well, I did make it lua (with infinite args), not sure if that actually made it more efficient or anything though Galobtter (pingó mió) 17:50, 13 August 2018 (UTC)[reply]
@Galobtter: it seems speedier from what I can tell. The template page throws an error right now but it's nothing that can't be solved with no include tags. Headbomb {t · c · p · b} 19:07, 13 August 2018 (UTC)[reply]

need help to localize parameter

Hello, i need to localize Module:Webarchive for bnwiki. I tried this, It works but not always. I listed some problems here. Please take a look, feel free to edit here (no need to explain anything to me). --আফতাবুজ্জামান (talk) 18:16, 26 August 2018 (UTC)[reply]

I'm guessing that your problem for |শিরোনাম২= and |ইউআরএল২= might be because parseExtraArgs() doesn't know about the bn equivalent names.
One of the things that I did for bn:Module:Citation/CS1 was to create a table that replaced bn digits with western digits in enumerated parameter names because Lua only understands western digits (the table for that is at bn:Module:Citation/CS1/Configuration and is named local_digits). You might need to do something similar if you will be supporting bn digits in your parameter names.
Trappist the monk (talk) 18:53, 26 August 2018 (UTC)[reply]
@Trappist the monk: Thank you for answer. Problem is i don't where to put it, which line. Even though i did this edit but i even don't know it was right or wrong. Could please do it there? --আফতাবুজ্জামান (talk) 20:10, 26 August 2018 (UTC)[reply]

date localization

Above problem is solved. But this module still have date related problem, you can see here (first two section). Can someone help. --আফতাবুজ্জামান (talk) 16:12, 27 August 2018 (UTC)[reply]

To make it work for dates, it would need to translate from Bengali to English early in the program, then back to Bengali late in the program .. this way the program remains mostly unmodified. It looks like there is মডিউল:ConvertDigit from English to Bengali - need a way to convert Bengali date to English. -- GreenC 20:50, 27 August 2018 (UTC)[reply]

Wikidata queries

Is it possible to do complex queries like this in Lua to Wikidata? -- GreenC 20:21, 27 August 2018 (UTC)[reply]

No, SPARQL queries are not supported directly on wiki. Queries have a future, but it was put off after the structured Commons work came in (and associated multi-content revisions). Outside of the mainspace, you can set up ListeriaBot for complex queries. --Izno (talk) 22:35, 27 August 2018 (UTC)[reply]
Oh well, as I thought. It's for a template used in infoboxes, which might be a bad idea anyway due to performance. Glad to hear it might/could happen though. -- GreenC 23:31, 27 August 2018 (UTC)[reply]
You can usually get infoboxes to work by traversing the edges between nodes if you're starting from a particular item, with the use of one or another of the Wikidata modules. --Izno (talk) 01:17, 28 August 2018 (UTC)[reply]
I don't know what traversing the edges between nodes means. Could the above query can be replicated with reasonable performance and without a major amount of Lua code? -- GreenC 01:58, 28 August 2018 (UTC)[reply]
No, it's not really feasible to search entries using the functionality exposed at present to Lua via the Wikibase client. There are 15,000,000 entities and 50,000,000 pieces of data, so without access to any form of indexing to query the database, any attempt to look through every item to find everything that matches particular criteria is going to be slow and resource-hungry. What Izno is suggesting is to start with an known item (usually the item connected to the page where the infobox is) and use links from there to read other items, then repeat until you arrive at the result you want. As an example look at the location function in Module:WikidataIB.
Lua's good for that sort of data manipulation, but you'll still need query-language based software, or similar, to efficiently do searches on the Wikidata database. --RexxS (talk) 15:26, 28 August 2018 (UTC)[reply]
Yes, I think I may have misunderstood the original intent. --Izno (talk) 15:36, 28 August 2018 (UTC)[reply]

Template:Demo demo_kill_categories alias nocat

I've did this change, but it doesn't seem to work. Can somebody with more Lua knowledge take a look? See example here: User:Andrybak/sandbox/demonocat -- note, that page is added to Category:Wikipedians in Russia, but shouldn't be. demo_kill_categories still works: User:Andrybak/sandbox/demonocat2. —⁠andrybak (talk) 11:27, 29 August 2018 (UTC)[reply]

you modified the function module(), but in this case it is not called, but rather get(), which you did not touch. קיפודנחש (aka kipod) (talk) 21:45, 31 August 2018 (UTC)[reply]
Thanks, קיפודנחש (aka kipod)! I've added it also to function get() —⁠andrybak (talk) 17:14, 1 September 2018 (UTC)[reply]
Resolved

Calculating moveable dates

The moveable date problem on Wikipedia is extensive. Infoboxes that display dates for a holiday with moveable dates largely need to be updated manually and there are thousands (many don't even bother trying). Currently there are two calculators Module:Easter and {{Hebrew year}} both of which I'm integrating into {{Moveable date}} (see Module:Calendar date/Events). These are good, but there are surprisingly no other calculators available on Wikipedia.

To get a sense how big this problem is, a list of holidays in the United States from a JavaScript program that determine moveable dates. For other countries. Dates can be complex like:

  • Tax Day: On April 15. If a Friday then postpone to next Monday. If Saturday or Sunday then next Tuesday.
  • Administrative Professionals Day: The Wednesday before April 28.

Notably, many of these dates are not calculated by the sun or moon, but by human decree which means they can change arbitrarily and thus need to be easily configured. But even dates that go by celestial guidance have trouble, for example {{Hebrew year}} can not accurately calculate dates for 3 of the Hebrew months as they are not fixed to the Gregorian calendar.

So this is a big messy problem with endless edge cases. My sense is we should try to translate a package like date-holidays or Nager.Date into Lua but I have no skills for those source languages. Then there is the argument by Mark Seeman to just store the dates and not do calculations. I'm doing this for certain holidays that can't be calculated eg. Module:Calendar_date/localfiles/Leil_Selichot

If we had a Lua program that could solve for some things, like "2nd sunday in May" or "3rd monday in January" it might go a long way to calculating holidays, and provide a system for building more complex queries like Tax Day. Any thoughts? -- GreenC 14:20, 3 September 2018 (UTC)[reply]

Module:Time has a function decode_dst_event() used to determine daylight saving time begin/end dates. The function takes "2nd sunday in May" or "3rd monday in January" and returns (for these examples) the ordinal (2 or 3), the day-in-the-week number (0 or 1) and the month number (5 or 1) or nil if the string can't be decoded or is malformed.
Trappist the monk (talk) 14:30, 3 September 2018 (UTC)[reply]
Sounds promising will take a look. -- GreenC 16:09, 3 September 2018 (UTC)[reply]
@GreenC: I guess you could use Wikidata items like date of Easter (Q51224536). Jc86035 (talk) 15:30, 3 September 2018 (UTC)[reply]
See two threads above - Wikidata would only have separate items pages for moveable holidays that are hard to calculate on Wikidata. For things like "2nd sunday in May" Wikidata can calculate it through a query, so it wouldn't have an item page. And without an item page Lua can't effectively retrieve a query (I think?). Also if a calculator is available locally that is probably going to be preferable to Wikidata. Such as Module:Easter. -- GreenC 16:02, 3 September 2018 (UTC)[reply]
@GreenC: Is this the sort of functionality you want?
  • {{#invoke:Sandbox/RexxS/CalcDate |getYearMonthDay |date=second Friday in June |year=2018}} → 2018-06-08
  • {{#invoke:Sandbox/RexxS/CalcDate |getYearMonthDay |last Friday in June |2018}} → 2018-06-29
  • {{#invoke:Sandbox/RexxS/CalcDate |getYearMonthDay |date=last Monday in February |year=2016}} → 2016-02-29
It needs some error handling and can be spruced up to return other formats, but it seems to do the job as I understand it. It's adapted from Module:Time per Trappist the monk's pointer. --RexxS (talk) 18:05, 3 September 2018 (UTC)[reply]
@RexxS: that is awesome. It will solve a bunch of them. The next question how to take it to the next level and solve for Native American Heritage Day: friday after 4th thursday in November. There are quite a few taking this form. Would this be an addition to the module, or could it be calculated by invoking multiple modules, such as with Module:Date suggested by Johnuniq (in this case adding +1 day to the output of getYearMonthDay). Or maybe RexxS/CalcDate could accept an offset option (-/+) to move the target day around relative eg. calculate for 4th thursday in November and add 1 day. -- GreenC 13:37, 4 September 2018 (UTC)[reply]
Sheesh I apologize for being so uninformed, apparently holiday infobox can already do some data calculations internally, see Patriots' Day. And for Thanksgiving, there is {{weekday in month}} that basically does the same thing. -- GreenC 15:01, 4 September 2018 (UTC)[reply]
Probably should focus next on calculators for non-Gregorian -> Gregorian, and otherwise difficult calculators like Easter. Various calendar systems are not currently available. Hindi being the most prevalent but also Japanese and Persian. -- GreenC 15:18, 4 September 2018 (UTC)[reply]

The request has been well satisfied but bear in mind that Module:Date can be used by other modules and includes stuff like this. Search Module:Date/example and its talk page for "Friday" to see examples. I never got around to finishing the documentation but Module:Age has more examples of what Module:Date can do. Time zones are not supported. If something is wanted from Module:Date, ask here or at its talk. Johnuniq (talk) 23:18, 3 September 2018 (UTC)[reply]

Most of it can be done in wikicode... Public holidays in the United Kingdom#England, Northern Ireland and Wales. Cabayi (talk) 16:11, 4 September 2018 (UTC)[reply]

Hi everybody! Google Code-in (GCI) will soon take place again - a seven week long contest for 13-17 year old students to contribute to free software projects. Tasks should take an experienced contributed about two or three hours and can be of the categories Code, Documentation/Training, Outreach/Research, Quality Assurance, and User Interface/Design. Do you have any Lua / template related idea for a task (needs documentation, or some code / code changes) and can imagine enjoying mentoring such a task to help a new contributor? If yes, please check out mw:Google Code-in/2018 and become a mentor! Thanks in advance! --AKlapper (WMF) (talk) 13:49, 9 September 2018 (UTC)[reply]