Wikipedia talk:Lua/Archive 12

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia

nbsp

Easy question this time: how do I produce a non-breaking space in lua? — Martin (MSGJ · talk) 19:50, 12 June 2023 (UTC)

 ?
Trappist the monk (talk) 20:35, 12 June 2023 (UTC)
Thank you. For some reason I thought that would produce the literal text. — Martin (MSGJ · talk) 21:06, 12 June 2023 (UTC)
It will produce the literal text  . Presumably, that will then be passed to a browser or similar software which will render it as a space. Lua doesn't have to do anything clever to achieve that. Certes (talk) 21:50, 12 June 2023 (UTC)

Help with Module:Location map

Hello.

I encountered a problem after uploading a map that uses Module:Location map, and was hoping to get help with it.

The file I uploaded is a close-up location map of Cairo and Giza, Egypt, to use it in articles such as 2023–24 Egyptian Premier League and 2023–24 Egyptian Second Division A, to indicate where each club is exactly located, since there are multiple clubs from these two governorates playing in the leagues (something similar to London in Premier League seasons' articles).

Once I uploaded the map and tried to use it, the following error appears:

Lua error in Module:Location_map/multi at line 27: Unable to find the specified location map definition: "Module:Location map/data/Egypt Cairo Giza" does not exist.

That error is clickable while in preview. When I click on it, a list of script errors appears, and to be honest, I have no clue how to solve these errors, as I have close to 0 experience with programming languages.

Can someone tell me what exactly I'm supposed to do to fix it? I'd really appreciate that. Thanks. Ben5218 (talk) 10:53, 15 June 2023 (UTC)

It's looking for a definition in Module:Location map/data/Egypt Cairo Giza. Pleasee see the documentation at Template:Location map — Martin (MSGJ · talk) 11:17, 15 June 2023 (UTC)
Thank you, MSGJ. I'll check it out. Instructions about everything I have to do should be located there and at Template:Location map/Creating a new map definition, right? Ben5218 (talk) 11:41, 15 June 2023 (UTC)

Read data outside the module namespace

Is there something like Module:Data that can parse JSON outside the module namespace? Specifically, I'd like to work with Wikipedia:New pages patrol/Backlog chart/daily in a template. – Joe (talk) 08:07, 19 June 2023 (UTC)

I believe the answer is no. A typical use is at {{London ward populations}} which reads items from Module:Data/London ward populations based on a key supplied as a parameter to the template. In other words, Module:Data requires a Lua table. However, a dedicated module could extract data from Wikipedia:New pages patrol/Backlog chart/daily rather easily. What do you need? Johnuniq (talk) 08:28, 19 June 2023 (UTC)
Well ideally, something like {{NPP backlog size|<date>}} and {{NPP backlog size|redirect|<date>}}, for an arbitrary date. Or would it be feasible to move the daily stats to the module namespace, MusikAnimal? – Joe (talk) 08:45, 19 June 2023 (UTC)
More than moving it would be required. The wikitext at Wikipedia:New pages patrol/Backlog chart/daily is currently in JSON. Module:Data needs the information stored as a Lua table. That's easy but MusikAnimal may not have much spare time. Are you saying you want a new template ({{NPP backlog size}}) and it should accept, for example, 2022-12-16 as a parameter and return 1355? What would your redirect template do? Johnuniq (talk) 08:53, 19 June 2023 (UTC)
Exactly. NPP used to rely quite heavily on Wikipedia:New pages patrol/Backlog chart to keep an eye on whether the backlog was growing or not. Since the graph extension doesn't appear to be coming back any time soon, I'm trying to put together a text-based 'dashboard' that could fulfil the same purpose. It would state the current size of the backlog (from User:DatBot/newpagesbacklog) and how much it is up/down compared to yesterday/last week/last month, sort of like a stock ticker. The "redirect" part is aspirational because as far as I can tell MusikBot doesn't track the size of the unreviewed redirect backlog (though the API does). – Joe (talk) 09:04, 19 June 2023 (UTC)
There is no need to look at the following links—I'm mentioning them for background if needed. GreenC and I cooperated on {{NUMBEROF}} which uses Module:NUMBEROF to read values written by a bot to c:Data:Wikipedia statistics/data.tab (Module:NUMBEROF/data translates that page into a Lua table). If the NPP info were written to Commons in a similar way, it would be easy for a module to extract any data required. A bot could also write data from the API (a module cannot access the API). I suggest you prepare a draft of what would be wanted in a sandbox using some of the current data. If you show the output that is wanted, it would be easier for people here to see what is needed. It might be easier for a module to return the whole wanted wikitext rather than implement a template which extracts items one-by-one. Johnuniq (talk) 09:19, 19 June 2023 (UTC)
mw.loadJsonData will read data in JSON format, and I think it will happily read from any page in that format, regardless of namespace. For example Module:Class reads the data at Module:Class/definition.json — Martin (MSGJ · talk) 09:20, 19 June 2023 (UTC)
Oh! I haven't been paying attention to new features. That makes reading the existing page even easier and means adding structured data at Commons is probably not required. A draft of the wanted output would still be desirable. Johnuniq (talk) 09:33, 19 June 2023 (UTC)
Putting the data on Commons is still sounds like a nice idea in the long term; this is a useful dataset that can't, as far as I know, be extracted from the database retrospectively. But as you say that'd require some bot work. For now, mw.loadJsonData did the trick. Thanks for the help, both! – Joe (talk) 10:46, 19 June 2023 (UTC)

Calculation in string

I have something like '2+3' stored as a string and I would like to calculate it as a number. tonumber doesn't work here. What's the best method? — Martin (MSGJ · talk) 09:09, 26 June 2023 (UTC)

tonumber won't work as it doesn't attempt to evaluate the expression. A quick glance at mw:Extension:Scribunto/Lua reference manual brings up mw.ext.ParserFunctions.expr(string), which works like the {{#expr: parser function and would likely work for your scenario. Aidan9382 (talk) 09:25, 26 June 2023 (UTC)
And there is an example at Module:Math#L-605. Johnuniq (talk) 09:57, 26 June 2023 (UTC)
Thanks, that's working nicely — Martin (MSGJ · talk) 11:25, 26 June 2023 (UTC)
depending on the source of the string and how much control you have over it, you may want to wrap it in pcall().
mw.ext.ParserFunctions.expr("my father is a holy man"), like any input that won't compute (e.g. 14 / 0) will throw an error.
it is preferable to do something like
local okeydokey, result = pcall( mw.ext.ParserFunctions.expr, myExpressionVar )
if okeydokey then
-- in this scope, "result" is good
else
-- handle the error here, like 
    result = someDefaultValue
end
peace - קיפודנחש (aka kipod) (talk) 20:15, 30 June 2023 (UTC)
Umm, are you sure? pcall( mw.ext.ParserFunctions.expr, "my father is a holy man" ) returns false for okeydokey and nil for result. Shouldn't the test be: if okeydokey then (without the not token)?
Trappist the monk (talk) 21:06, 30 June 2023 (UTC)
sorry, you are correct. in original code i had the error handling in first hunk, and decided it looks better when the first hunk is success, but forgot to remove the "not"... doing it now (the name of the "success variable is a strong hint that true means success and false means error).
peace. קיפודנחש (aka kipod) (talk) 22:43, 30 June 2023 (UTC)

Unexpected result when setting table value to nil

Consider the following code (from Module:Sandbox/MSGJ):

function p.main(frame)
 args = frame.args
 args.category = nil
 return args.category
end

What would you expect from {{#invoke:Sandbox/MSGJ|main|category=Foo}} — Martin (MSGJ · talk) 14:20, 6 July 2023 (UTC)

I would expect that it returns "Foo"; the frame.args object uses a custom metatable that handles gets so the value overwrite is ignored. * Pppery * it has begun... 14:24, 6 July 2023 (UTC)
I can overwrite it to other values. Why is nil different? And is there any method I can set it to nil? — Martin (MSGJ · talk) 14:25, 6 July 2023 (UTC)
You can't overwrite to nil because the aforementioned metatable is based on the __index metamethod, which, per the documentation, is used when a table access t[key] would return nil. I don't know of any way around this, although if you were to use Module:Arguments instead of reading directly from frame.args then that handles setting nil properly. * Pppery * it has begun... 14:33, 6 July 2023 (UTC)
You can copy the table with a for k, v in pairs( args) do loop. Then you can set the values to nil. —  Jts1882 | talk  14:54, 6 July 2023 (UTC)
I don't know what to expect because I gave up trying to understand how args works (with or without Module:Arguments) for anything other than a read-only table. Spelling out Pppery's reply, args.category = nil actually removes args.category from args so when return args.category is executed, the value does not exist in the table and that causes the __index function attached to args to be called, and that reads the underlying value ('Foo') from the wikitext. The generic method for manipulating frame.args is to clone args and adjust it as wanted, then use the clone with newChild and pass the result to whatever is needed. There may be a way of avoiding that complex workaround in whatever the use case is. Johnuniq (talk) 04:13, 7 July 2023 (UTC)
I also personally try to treat frame.args as read-only, even if you can overwrite it (with things other than nil). It's more in keeping with the functional ethos of minimizing mutation and avoiding what is often treated as global state in many of our modules. As alternatives indeed, either you can clone the whole table and then mutate the resultant, or you can create your own variables that take on relevant values. I prefer this second option myself because this also allows you to give the variables nicer names than what are often abbreviations and smushed words and duplicate parameter names in the template interface. Izno (talk) 04:53, 8 July 2023 (UTC)

Thanks everyone. This created a bug in my code which I found really hard to find! Basically I am calling a module which has nearly the same set of arguments, so for convenience I just passed the whole table of arguments from the calling module. But it turns out one argument ("category") was conflicting as the other module was using this for a different purpose. So I thought I would just set that one to nil before sending the table but that didn't work either. So I am now doing as recommended and constructing a new table of arguments for the other module. — Martin (MSGJ · talk) 10:53, 9 July 2023 (UTC)

Testing the new Module:Params

I wrote a new general-purpose module, Module:Params, somewhat similar to Module:TemplatePar but more flexible and powerful. The module is already being used by {{Template journal}} and {{Template journal inline}}. If you people have time I would like to ask to have a look at it, test it, collect ideas, help with the documentation, report bugs. --Grufo (talk) 01:17, 10 July 2023 (UTC)

We already have too many modules in this area. We don't need even more ways to do the same thing. * Pppery * it has begun... 01:25, 10 July 2023 (UTC)
Hi Pppery, thank you for your early feedback. If I had known a module that did the same things I would not have written this new module. But the problem is that I did not know any other way to overcome the limitation of accepting maximum 50 parameters and drastically reduce the complexity like i did in {{Template journal}} and {{Template journal inline}}. I suggest you try and experiment with Module:Params, you might be pleased by its simplicity and the possibilities that it offers. --Grufo (talk) 01:33, 10 July 2023 (UTC)

Make changes to copied table element not reflect on old target elements of copying

I recently updated Module:Wikipedia ads/data. Part of the implementation fixes the id field of a table element (skippedEntries[i]) before copying it into the output tables (one of them is list[id]) when needed, multiple times. However, it has a problem. For some reason, after I've copied the first skippedEntries[i] with id 40, if I change the skippedEntries[i]'s id to another value, the old element with id 40 also turns its id into the updated id. How do I fix that? Aaron Liu (talk) 01:32, 16 July 2023 (UTC)

I'm having trouble thinking at the moment so take what I say with caution. However, if you have a table t, and then execute a = t; b = t, variables a and b refer to the same table. Executing a.id = 42 will also set b.id to the same value. If you want different different tables in a and b, you have to use a = mw.clone(t) and same for b. I would rearrange the code. I gather that Module:Wikipedia ads/list is loaded somewhere with mw.loadData. In that case (and if it's not used in another way), you can delete Module:Wikipedia ads/data and edit Module:Wikipedia ads/list to return the fixed table. Maybe that's a bit adventurous although quite achievable. If data is kept, I would edit it to construct the missing table rather than cloning it: t = {}; t.id = ...; t.image = ...; and so on for the other fields, then insert t. Or just use clone. Johnuniq (talk) 03:46, 16 July 2023 (UTC)
/data returns an additional table so I don't think I should do that. I'll try clone tomorrow. Aaron Liu (talk) 03:59, 16 July 2023 (UTC)

Producing a list

I have a template (Template:WPBannerDoc) which outputs an asterisk followed by text. When called with wikitext it produces an unordered list. I am trying to call this template from a module via frame:expandTemplate but the literal text is displayed without the list structure. Even prefixing <br> doesn't help. You can see the output at Template:WikiProject Medicine/sandbox#Parameters. My question is: how can I get my bullet points working correctly by using this template? — Martin (MSGJ · talk) 19:02, 20 July 2023 (UTC)

Is this a case where you need to do something like return frame:preprocess ('* '''class''' – valid values are listed ...')?
Trappist the monk (talk) 19:28, 20 July 2023 (UTC)
At Template:WikiProject Medicine/sandbox#Parameters, the Parameters section at the bottom showed "*class – valid values are ... *importance – valid values are ..." where the asterisks were displayed. I think my edit at Module:WikiProject banner/templatepage/sandbox has resolved the issue. I inserted some newlines so asterisks were at the start of a physical line. I hope there are no bad side effects. Johnuniq (talk) 01:27, 21 July 2023 (UTC)
Ah nice, thanks. I was using '<br>' and you were used '\n'. I should have known. — Martin (MSGJ · talk) 07:20, 21 July 2023 (UTC)

Help with Russian module

Wikipedia:Village pump (technical) § Modify a module could use a few eyes from people to see if the Russian module can be adjusted as requested. Izno (talk) 21:00, 26 July 2023 (UTC)

Invoke detection

What is the easiest way for a module to detect if it has been called via #invoke or from a wrapper template? — Martin (MSGJ · talk) 16:46, 27 July 2023 (UTC)

I believe the following works.
local function main(frame)
	local result
	if frame == mw.getCurrentFrame() then
		result = "Module called via #invoke"
	else
		result = "Module called via require or debug console"
	end
	return result
end
return { main = main }
Let me know if you confirm this works. Johnuniq (talk) 04:32, 28 July 2023 (UTC)
Thanks. That is interesting, but does not answer my specific question which is about distinguishing between #invoke and wrapper template (which is also calling #invoke). I think what I want is to check if there is a parent frame or not. — Martin (MSGJ · talk) 20:57, 28 July 2023 (UTC)
Try frame:getParent():getTitle() (if frame is available) or mw.getCurrentFrame():getParent():getTitle() (if not). Maybe something in the title would be helpful. Johnuniq (talk) 09:58, 30 July 2023 (UTC)
If I understand the question correctly, then this will throw an error if the module has been called via a direct invoke. The existence of a parent frame at all means there is a wrapper template, so you just need to check if mw.getCurrentFrame():getParent() is not nil. On a side note, it’s more reliable to check mw.getCurrentFrame() instead of frame unless you can guarantee that the frame object is actually the frame for the current page, which may not always be the case. Theknightwho (talk) 14:29, 31 July 2023 (UTC)
Ignore all of that - I forgot that the original frame has the module title, and the parent frame is the page with the #invoke: on it. The actual solution is to check whether mw.getCurrentFrame():getParent():getTitle() == mw.title.getCurrentTitle().fullText. This checks whether the title of the page with the #invoke: (i.e. the parent frame) is the same as the title of the page being rendered (i.e. the current title). If there is no wrapper template, these will be the same. If there is one, they'll be different. Theknightwho (talk) 17:26, 31 July 2023 (UTC)
Ummm... are you sure? I have used the value returned by mw.title.getCurrentTitle().namespace as a way to limit categorization to article name-space only. That means that mw.title.getCurrentTitle().fullText returns the name of the article that contains the #invoke: whether #invoke: is directly instanced in the article or hidden inside a template instance. If mw.title.getCurrentTitle() returned a title object for the template that holds the #invoke:, mw.title.getCurrentTitle().fullText would return the name of the template; mw.title.getCurrentTitle().namespace would always return the number for the Template namespace (it doesn't).
Trappist the monk (talk) 17:46, 31 July 2023 (UTC)
@Trappist the monk - yes, that’s correct. mw.title.getCurrentTitle().fullText is the page being rendered (usually an article). mw.getCurrentFrame():getParent():getTitle(), on the other hand, is always the page with the #invoke on it. If there is a wrapper template, these will be different; if there is no wrapper template, they will be the same. You need to compare the fullText field of the current title object, because the title stored in the frame object is a literal string. Theknightwho (talk) 04:51, 1 August 2023 (UTC)

Maintain state between Module invocations

I originally posted Wikipedia:Help_desk#How_to_update_a_LUA_global_variable_between_multiple_Module_function_calls_from_a_wiki_page? about essentially maintaining the state of a global variable between multiple invocations of a Module from a single article page. The answer was that preserving the state of a global variable between multiple invocations is not possible. That in itself, begs the question, wouldn't it make LUA much more useful if it could preserve state within a wiki page? Is this limitation self-imposed by the Wiki infrastructure or cannot be done due to technical limitations in the Scribunto/Lua interface? Anyways, as an alternate solution, is there a way I can feed in multiple lines of data via Module parameters so I can maintain a counter that is used in formatting Module output? Or am I going to run into a Module parameters length limitation as some point?
For example:

{{#invoke:Sandbox/RedWolf|list|delim=/|mountains=
Mount Logan /m/5959/-1/[[Saint Elias Mountains]]/fa=1925/notes=Highest point in Canada/refs=<ref name=fr>First reference</ref>
Mount Robson/m/3954/2829/Rainbow Range/fa=1913/notes=Highest point in the Canadian Rockies
Mount Temple (Alberta){{!}}Mount Temple/m/3543/1544/[[Bow Range]]/fa=1894
}}

RedWolf (talk) 18:09, 3 August 2023 (UTC)

You will probably run into post expansion transclusion limit with that approach. And also, that's not wikitext which is not friendly for users. Izno (talk) 18:19, 3 August 2023 (UTC)
I haven't examined the above example but I have been told that it is a design decision that templates and modules have no state information. The idea is that different people should be able to simultaneously edit different sections of an article and preview/publish should not depend on other parts of the page. Johnuniq (talk) 23:26, 3 August 2023 (UTC)

Module:Mock title

I made a module for mocking Scribunto title objects. It can be used when testing code that uses title constructors like mw.title.new; normally the output of test code like this would depend on the state of the relevant wiki pages (and so people could break your tests by editing them), but by using mock titles you can make your tests independent of the state of the wiki. Please take a look at it and let me know if you have any feedback. — Mr. Stradivarius ♪ talk ♪ 13:47, 23 August 2023 (UTC)

Conversion of Template:Marriage to Lua

I checked the source for Template:Marriage and it keeps on using so much code and parser functions. I suggest that the conversion should make the template more workable. RMXY (talk) 05:18, 20 September 2023 (UTC)

I agree that a conversion would make a lot of sense. Do you fancy learning lua? — Martin (MSGJ · talk) 07:08, 20 September 2023 (UTC)
I want to learn how to do Lua. RMXY (talk) 08:25, 22 September 2023 (UTC)
This is a solution in search of a problem. The template's quest for omniscience and built-in opinions should be pared back, rather than entrenching them by creating a module. * Pppery * it has begun... 14:22, 22 September 2023 (UTC)
What do you mean by "built-in opinions"? I'm looking at it and not seeing a problem. Looks like a template that provides considerable utility.  — SMcCandlish ¢ 😼  19:07, 22 September 2023 (UTC)
See Template talk:Marriage/Archive 8#Use of circa for an example of what I mean. I may well hold a minority opinion here, though. * Pppery * it has begun... 22:19, 22 September 2023 (UTC)
I see what you mean, but this seems like it should be reasonably easy to fix in the code, namely by no longer "helpfully" policing the input. At bare minimum, something like |circa=y parameter could turn those checks off?  — SMcCandlish ¢ 😼  22:34, 22 September 2023 (UTC)
My point is that once you remove the input policing it will hopefully reach the point where it's no longer complicated enough to warrant a Lua module. * Pppery * it has begun... 00:05, 23 September 2023 (UTC)

Help with understanding Lua module

I'm very new to Lua and am trying to understand how Module:Settlement short description uses the contents of the infobox to automatically generate a short description for the page if one does not exist already. I can tell this is all done in the p.main() function through usage of p.shortdesc(), but I don't understand where frame comes from. It looks like it would contain the specific contents of the page. How can I provide the module with Wikipedia article titles, such as Morning Glory, Texas or Stoneham-et-Tewkesbury for example, to see how the text parameter provided to p.shortdesc() is built in p.main()? Then once I am able to do so, how can I view the contents of variable like subdivision_names or location within p.main? BaduFerreira (talk) 15:38, 27 September 2023 (UTC)

The frame object contains all the parameters/arguments that is passed to the module. There are only really two frames you need to know about: frame.args is a table of arguments from the template that calls #invoke, and frame:getParent().args is a table of arguments passed by the page that called that template. This particular module only uses the latter. I'm not familiar with the code but I believe it is mainly using the parameters that are defined in Template:Infobox settlement. The actual title of the article is only used once, rather obliquely, with mw.title.getCurrentTitle().text — Martin (MSGJ · talk) 20:29, 28 September 2023 (UTC)
Okay, that makes sense. Thank you for the link, this looks like a very helpful resource. Is it possible to dump the table of arguments that any given page using this template passes to the module? I'd like to play around with the module and I think concentrating my efforts offline to a local copy would be more effective and less disruptive. BaduFerreira (talk) 22:10, 28 September 2023 (UTC)
mw.dumpObject (frame.args) – dumping just frame is interesting too.
Results are available under the Lua logs dropdown in the Parser profiling data dropdown when you preview an article (or testcases page) that uses your module.
Trappist the monk (talk) 22:55, 28 September 2023 (UTC)
What do you mean by results? Would that be the output of mw.dumpObject (frame.args)? I'm not sure where I would execute that function. Additionally, where would I find the Parser profiling data dropdown? I don't know what you mean by preview article (I thought maybe edit preview but I can't find anything there). Hope you don't mind all the questions 🙂 BaduFerreira (talk) 00:50, 29 September 2023 (UTC)
You edit the module and add the line somewhere in the function where frame is passed as an argument. Do not save the edit (you will finish by abandoning it, leaving the module unchanged). Underneath the edited module, find "Preview page with this template" and paste the title of a page where the module is used. Click Show preview to see how that page would look if the edit to the module were saved. Then the stuff at the bottom of the page should show the dump. Johnuniq (talk) 01:02, 29 September 2023 (UTC)
Ah okay, I see. I didn't realize I could do that. I'm able to preview a page that uses Module:Settlement short description after adding the mw.dumpObject(frame.args) function to p.main(), but I'm getting nil as the output so I'll keep poking around. Thank you everyone for all the help so far! BaduFerreira (talk) 01:55, 29 September 2023 (UTC)
Sorry, it's mw.logObject(frame.args) (log, not dump; dump gives a string). However, I just tried it (using Anah as the preview page) and the output is just table#1 { metatable = table#2 }. That's because args is a magic table that doesn't do anything until you ask for a specific argument. You would need something like mw.logObject(frame:getParent().args.short_description) but that outputs nil because no parameters are passed to the template. Johnuniq (talk) 02:21, 29 September 2023 (UTC)

The syntax for Template:Weather box is unnecessarily verbose as each data entry receives its own row. I have no prior knowledge of Lua and am trying to condense the template:

Example: Template:New York City weatherbox would be condensed to something like this:

{{Compact weather box
|location = New York City
|source 1 = [[NOAA]] (relative humidity and sun 1961–1990; dew point 1965–1984)<ref name = "New York City Weatherbox NOAA" >{{cite web |url=https://w2.weather.gov/climate/xmacis.php?wfo=okx |title = NowData – NOAA Online Weather Data |publisher = [[National Oceanic and Atmospheric Administration]] |access-date = May 4, 2021}}</ref><ref name="New York City Weatherbox NOAA txt">{{cite web |archive-url=http://web.archive.org/web/20210504224841/https://www.ncei.noaa.gov/access/services/data/v1?dataset=normals-monthly-1991-2020&startDate=0001-01-01&endDate=9996-12-31&stations=USW00094728&format=pdf |archive-date=May 4, 2021 |url=https://www.ncei.noaa.gov/access/services/data/v1?dataset=normals-monthly-1991-2020&startDate=0001-01-01&endDate=9996-12-31&stations=USW00094728&format=pdf |publisher=[[National Oceanic and Atmospheric Administration]] |title=Summary of Monthly Normals 1991–2020 |access-date=May 4, 2021}}</ref><ref name = noaasun>{{cite web|title=New York Central Park, NY Climate Normals 1961−1990|url=ftp://ftp.atdd.noaa.gov/pub/GCOS/WMO-Normals/TABLES/REG_IV/US/GROUP2/00305801.TXT|publisher=[[National Oceanic and Atmospheric Administration]] |access-date=July 18, 2020}}</ref>
|source 2 = Weather Atlas<ref name="Weather Atlas NYC">{{cite web |url=https://www.weather-us.com/en/new-york-usa/new-york-climate |title=New York, New York, USA - Monthly weather forecast and Climate data |publisher=Weather Atlas |access-date=July 4, 2019 }}</ref>
|units = imperial |preferred units = imperial
|temp color = default |precip color = green |snow color = blue |humidity color = blue
<!-- month     Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec  Year-->
|record high   |72  |78  |86  |96  |99  |101 |106 |104 |102 |94  |84  |75
|monthly high  |60.4|60.7|70.3|82.9|88.5|92.1|95.7|93.4|89.0|79.7|70.7|62.9|97.0
|high          |39.5|42.2|49.9|61.8|71.4|79.7|84.9|83.3|76.2|64.5|54.0|44.3
|mean          |33.7|35.9|42.8|53.7|63.2|72.0|77.5|76.1|69.2|57.9|48.0|39.1
|low           |27.9|29.5|35.8|45.5|55.0|64.4|70.1|68.9|62.3|51.4|42.0|33.8
|monthly low   |9.8 |12.7|19.7|32.8|43.9|52.7|61.8|60.3|50.2|38.4|27.7|18.0|7.7
|record low    |-6  |-15 |3   |12  |32  |44  |52  |50  |39  |28  |5   |-13
|precip        |3.64|3.19|4.29|4.09|3.96|4.54|4.60|4.56|4.31|4.38|3.58|4.38
|snow          |8.8 |10.1|5.0 |0.4 |0.0 |0.0 |0.0 |0.0 |0.0 |0.1 |0.5 |4.9
|precip day threshold = 0.01 in
|precip days   |10.8|10.0|11.1|11.4|11.5|11.2|10.5|10.0|8.8 |9.5 |9.2 |11.4
|snowy day threshold = 0.1 in
|snowy days    |3.7 |3.2 |2.0 |0.2 |0.0 |0.0 |0.0 |0.0 |0.0 |0.0 |0.2 |2.1
|humidity      |61.5|60.2|58.5|55.3|62.7|65.2|64.2|66.0|67.8|65.6|64.6|64.1
|dew point     |18.0|19.0|25.9|34.0|47.3|57.4|61.9|62.1|55.6|44.1|34.0|24.6
|sun           |163 |163 |213 |226 |257 |257 |268 |268 |219 |211 |151 |139
|percent sun   |54  |55  |57  |57  |57  |57  |59  |63  |59  |61  |51  |48
|uv            |2   |3   |4   |6   |7   |8   |8   |8   |6   |4   |2   |1
}}

In addition to having only one row for each monthly statistic, rather than 12-13 rows, the suggested configuration would resemble a table, allowing better readability and editing of data. Unlike Template:Weather box/concise C and Template:Weather box/concise F, this template would support all the data provided in Template:Weather box. For the rows with 12 values rather than 13 (everything except monthly high and monthly low), the yearly value would be automatically calculated. Crossover1370 (talk | contribs) 19:12, 30 September 2023 (UTC)

I agree that would be a better procedure and is something I thought about that while implementing Module:Weather box but it was already a bit over human comprehension. Some delimiter other than pipe would be used so each row could be parsed. Module:Football manager history does something similar in that it extracts fields from text rows. Another to-do item is to use mw.html to generate the table rather than wikitext. Johnuniq (talk) 23:36, 30 September 2023 (UTC)
Would the comma be an acceptable delimiter? (as in |high = 40, 42, 49, 62, 71, 80, 85, 83, 76, 65, 54, 44)? Would there have to be quotation marks, as in |high = "40, 42, 49, 62, 71, 80, 85, 83, 76, 65, 54, 44"? I'm trying to develop this myself but I know nothing about Lua or how it is used in Wikipedia. Crossover1370 (talk | contribs) 01:13, 1 October 2023 (UTC)
I guess comma would never conflict with any of the parameters that weatherbox expects (if a value could ever contain a comma, you would want to pick a different delimiter). It might be ok to use spaces with a dash for missing items. Johnuniq (talk) 01:35, 1 October 2023 (UTC)
Would there have to be quotation marks at the beginning and the end of the sequence of values? As in: |high = "40, 42, 49, 62, 71, 80, 85, 83, 76, 65, 54, 44"? Or would |high = 40, 42, 49, 62, 71, 80, 85, 83, 76, 65, 54, 44 (without quotes) be acceptable? Crossover1370 (talk | contribs) 01:55, 1 October 2023 (UTC)
Quotes not needed. Everything in a template is a string (1.5 is three ASCII characters). Johnuniq (talk) 02:51, 1 October 2023 (UTC)
Just use whitespace as delimiter instead of comma for even more readable template syntax: mw.text.split(datarow, '%s+') Dexxor (talk) 08:17, 1 October 2023 (UTC)

JSON

Do we have a Lua module that can read a JSON table, something equivalent to Module:Data? I found Module:Jf-JSON but it looks way more complicated than I need. — Martin (MSGJ · talk) 11:33, 19 July 2023 (UTC)

mw.loadJsonData, mw.text.jsonDecode, and mw.text.jsonEncode. mw.ext.data.get may also be relevant. Izno (talk) 16:25, 19 July 2023 (UTC)
I'm thinking we could adapt Module:Data so that it can read JSON pages as well. There could be a parameter to switch between the modes or possibly it could be deduced using mw.title.contentModel — Martin (MSGJ · talk) 20:55, 19 July 2023 (UTC)
Do you want to access the data on the JSON page from Lua, or from a template? (From your later post, I'm guessing from a template.) To provide access from a template, if it's just one JSON page, you could create a simple wrapper module that calls mw.loadJsonData on it, and returns the value from the call. This module can then be used as an argument to Module:Data. If the template is using a lot of data from the JSON page, converting the template to a Lua implementation may be worth considering. isaacl (talk) 17:58, 29 September 2023 (UTC)
A module which I could invoke in a template would be just fine. Could an additional function be added to Module:Data to call mw.loadJsonData and then pass to its main function? I'm not familiar with metatables so don't want to touch that module! — Martin (MSGJ · talk) 14:47, 4 October 2023 (UTC)
In a kind of kludgy manner. The syntax {{#invoke:Data|Module:''some module''|...}} maps to Scribunto taking the object returned by Module:Data and invoking a method called Module:some module on it, which means using Module:some module as a key to the underlying table in the object, and treating the return value as a function. Since Module:Data can't hardcode functions for every single possible module that might be used with it, it sets up a metatable with an __index() function that returns a function. This function uses the key value that was passed to __index() as the name of the module page to access. The essential logic of this function could be extracted into a helper function, and the __index() function could be modified to treat specific values differently: say, a key in the format of JSON:page name could return a new utility function that calls mw.loadJsonData() on the specified page and then passes its return value to the helper function. isaacl (talk) 16:43, 4 October 2023 (UTC)
Not going to pretend I understood half of that! But if you would have time to sandbox some code I will gladly test it, and maybe other people would find this useful too — Martin (MSGJ · talk) 20:21, 4 October 2023 (UTC)
Module:Data doesn't have any test cases, so I'd have to first figure out its use cases and create tests in order to do regression testing. Thus unfortunately it's a bigger project than I'm looking to do at present. If you could describe your intended use case, maybe a simpler solution could be found. isaacl (talk) 02:06, 5 October 2023 (UTC)
My immediate needs were met by Module:Women in Green event (main function) which was certainly simple enough. Don't worry if you haven't got time, this is on my long-term wishlist. — Martin (MSGJ · talk) 08:00, 5 October 2023 (UTC)

Colon

I notice that string.upper(s) is equivalent to s:upper() - is that correct? Why is the "string" not needed in the second format? — Martin (MSGJ · talk) 13:28, 6 October 2023 (UTC)

This is correct behaviour, and I believe is called a method call.
If you call a function of an object using : instead of ., the first argument will automatically become the object the call was made from. For example, t:xyz(...) is just an alternate way of typing t.xyz(t, ...)
Since all strings have the string functions as methods (E.g. ("").upper is string.upper), this means s:upper() is functionally acting as string.upper(s).
You can see an example in mw:Extension:Scribunto/Lua reference manual § Function calls. There's also some special rules when using : to define a function, which you can read about at the bottom of this section on the lua manual. Aidan9382 (talk) 13:59, 6 October 2023 (UTC)
Thank you, that's helpful. I had no idea you could replace the word "string" with any string. Is that part documented somewhere? — Martin (MSGJ · talk) 20:54, 6 October 2023 (UTC)
This behavior is part of Lua but I forget where I saw it documented originally. Whether or not s:upper() works depends on what s is. It needs to be based on a table with a member called upper and that member has to be a function. Strings in Lua (but not mw.ustring) work like that. Johnuniq (talk) 23:06, 6 October 2023 (UTC)
The reason this logic applies to string objects is because their metatable's __index is the string table.lua docs This means attempting to index (access a member of) a string object will actually index the string table for that object. Aidan9382 (talk) 06:32, 7 October 2023 (UTC)

Module to sum table column

I am an absolute beginner in lua and wanted to develop a module Module:Sandbox/Miria~01 that automatically sums the values ​​of the columns in a wiki table like this one created in my sandbox User:Miria~01/sandbox.

Games Athletes Gold Silver Bronze Total Rank
2008 Beijing 92 0 1 2 3 61
2012 London 116 1 1 2 4 43
2016 Rio de Janeiro 103 2 4 2 8 32
2020 Tokyo 87 3 1 5 9 28
2024 Paris future events
2028 Los Angeles
2032 Brisbane
Total 6 7 11 24 67

edited table on 11 September 2023 to show no error, original in the revision history Wikipedia_talk:Lua&oldid=1174743806

last row (total) with invoke to load module:
 
!colspan=2| Total !! {{#invoke:Sandbox/Miria~01|calculateSum|Gold|User:Miria~01/sandbox}} !! {{#invoke:Sandbox/Miria~01|calculateSum|Silver|User:Miria~01/sandbox}} !! {{#invoke:Sandbox/Miria~01|calculateSum|Bronze|User:Miria~01/sandbox}} !! {{#invoke:Sandbox/Miria~01|calculateSum|Total|User:Miria~01/sandbox}} !! [[All-time Olympic Games medal table|67]]

However, only zeros are ever generated as a sum. I would be grateful for any small help.

local p = {}

function p.calculateSum(frame)
    local args = frame.args
    local column = args[1]
    local wikitext = args[2]
    local sum = 0

    -- Iterate through the rows of the table
    for row in mw.text.gsplit(wikitext, "\n") do
        -- Check if the row contains the specified column
        if mw.ustring.find(row, "|" .. column .. "|") then
            -- Extract the value from the specified column
            local value = mw.ustring.match(row, "||%s*([0-9]+)%s*||")
            if value then
                -- Attempt to convert the value to a number, or default to 0 if conversion fails
                local numValue = tonumber(value)
                if numValue then
                    sum = sum + numValue
                end
            end
        end
    end
    return tostring(sum)
end
return p

Miria~01 (talk) 11:28, 10 September 2023 (UTC)

@Miria~01: It looks like you are trying to parse the contents of User:Miria~01/sandbox, but your code above instead tries to parse the literal string User:Miria~01/sandbox as a wikitable. Instead you want to fetch the content of the page using title:getContent(). So instead of this:
    local wikitext = args[2]
You can do this:
    local wikitext = mw.title.new(args[2]):getContent()
Best — Mr. Stradivarius ♪ talk ♪ 11:43, 10 September 2023 (UTC)
Thanks for the quick reply. The suggestion with title:getContent() obviously makes sense. Unfortunately only zeros are still generated. But I'll take a look at the module Module:USN fleet totals from User:Trappist the monk, how he did it, to hopefully find a solution for my issue. Miria~01 (talk) 12:56, 10 September 2023 (UTC)
Not going to work as you want it to work because args[2] is just the text string User:Miria~01/sandbox.
I wrote some code to render List of current ships of the United States Navy § Fleet totals by extracting the appropriate data from tables. See {{USN fleet totals}}, Module:USN fleet totals, and Module:USN fleet totals/data. You might want to look at that code to see how I did it.
I can imagine difficulties in the future because editors have varying beliefs regarding how wikitext should be formatted. It might be best to have your module create the whole table from data stored in a module's subpage. There would be no parsing required for that.
Seems odd to me that MediaWiki doesn't have Javascript to sum table contents. After all, MediaWiki does provide Javascript to sort columns so it would seem that they could also supply a script to sum columns and/or rows. That they don't suggests that there are difficulties that I am not aware of.
Trappist the monk (talk) 12:04, 10 September 2023 (UTC)
Thanks for the suggestion, I'll definitely take a look at your modules and try to build on that with the previous save data in a module's subpage, summing the columns/rows in tables.
I'm actually also surprised that, if at all, calculations can only be made on Wiki using {{#expr:expression}}, but only explicitly numbers and not, for example, cells (cell_ID could be assigned) from tables. Miria~01 (talk) 12:59, 10 September 2023 (UTC)
The line if mw.ustring.find(row, "|" .. column .. "|") then is searching for text "|Gold|" which never gets a result (hence sum=0). You want to find lines beginning with "|align=left|" or just "|" and then iterate the results of mw.ustring.match(row, "||%s*([0-9]+)%s*||"). You need some way of deciding which column to extract or output all the sums in a single call. —  Jts1882 | talk  14:01, 10 September 2023 (UTC)
Which all complexity is why I suggested building the table on the fly from data in a ~/data module...
Trappist the monk (talk) 14:20, 10 September 2023 (UTC)
Yes, data modules are much more flexible. I've used them before at Module:Goalscorers and Module:SportsRankings.
In the meantime, I made a quick and dirty version of Module:Sandbox/Miria~01 that automatically sums the values of the columns Gold, Silver, Bronze and Total and outputs the sums for the table in User:Miria~01/sandbox. —  Jts1882 | talk  14:58, 10 September 2023 (UTC)
All added a column option "All" to output the sums as four table cells in one module call. —  Jts1882 | talk  15:07, 10 September 2023 (UTC)
Thank you very much, I had a wrong thought how to recognize the correct line with the value. Also realize that data-modules is actually the best and cleanest solution.
In the end, the driving force was that the total sum of medals in the medal tables of the individual nations (by Olympic event, by sports, etc.) at the Olympic Games (e.g. Russia_at_the_Olympics#Medal_tables) at the Olympic Games is correct. Since in the case of stripped medals (stripped after several years due to doping), individual users change accordingly the entry for the event, but neglect the total sum or change the entry for the year, but neglect to change it also at the sport itself and so incorrect numbers arise. Miria~01 (talk) 16:18, 10 September 2023 (UTC)
As a note, "align=left" is deprecated/obsolete HTML and is likely to be removed. In general, this whole endeavor is indeed brittle at best. Izno (talk) 16:24, 10 September 2023 (UTC)
Just because I've not done much with the html library, this seemed like a useful learning opportunity so I have hacked Module:Sandbox/trappist the monk/html which creates a table along the lines of the table that Miria~01 posted in the OP. It ignores future events (I'm not sure that en.wiki looks favorably on stuff that has not yet occurred). The experiment relies on two tables; one for the all-time ranking (bottom right table cell) and one containing all of the necessary row data. To test it add this to a sandbox:
{{#invoke:Sandbox/trappist_the_monk/html|html_table_build|srb|sog}}
Trappist the monk (talk) 16:46, 10 September 2023 (UTC)

Just for completeness: I created for my request in Module:Sandbox/Miria~01/sumMedals, that after specifying a targetClass as args[1], the type of medals should be searched for. e.g. for summer class="summerMedals" and for winter class="winterMedals". For the existing medal tables of all countries ("xxx"_at_the_olympics, e.g. Croatia at the Olympics) class="summerMedals" or class="winterMedals" would then have to be inserted into the table rows. At the same time, the infbox for the individual countries can also be updated directly on the same page

| gold  =  {{#expr: {{#invoke:Sandbox/Miria~01/sumMedals|calculateSum|summerMedals|Gold|{{FULLPAGENAME}}}} + {{#invoke:Sandbox/Miria~01/sumMedals|calculateSum|winterMedals|Gold|{{FULLPAGENAME}}}}}}

In Wikipedia talk:WikiProject Olympics#Module to calculate sum in medal tables(+update of infobox) I explained this in more detail using an example. Of course it's not the cleanest solution, but I think it's okay temporarily. The goal, however, is a large-scale database that automatically creates the correct medal tables in the pages for the individual countries based on the data at the pages of the individual Olympics medal table e.g 2014 Winter Olympics medal table.
Miria~01 (talk) 11:44, 11 September 2023 (UTC)

@Miria~01 I think that I have finish playing around. My module at Module:Sandbox/trappist the monk/html and Module:Sandbox/trappist the monk/html/data renders summer and winter tables for Serbia and Mexico. Expanding to support other countries should mostly be a matter of clerical drudgery though no doubt, an awb script could be written to extract the pertinent data from articles using plain wikitext tables. The module also has an exported function to calculate total numbers of gold/silver/bronze medals for use in infoboxen. See this version of my sandbox for example renderings.

The modules should be sufficiently documented to make expansion and maintenance of ~/data relatively easy.

Trappist the monk (talk) 16:42, 11 September 2023 (UTC)

Adding line to Module:Interlinear

I want to add a parameter to {{fs interlinear}} to allow for a right-to-left gloss for Semitic languages. I tinkered a little bit with the HTML that the template produces, and it seems like all that's needed to do this is change line #44 of Module:Interlinear so that it can read float: right; rather than float: left; if a certain parameter (perhaps |RTL=yes) is set. I asked the person who usually edits that template, but their last edit was in April so I don't think I'm hearing back on that anytime soon. Can someone here help me figure out how to make this alteration? Eievie (talk) 01:57, 19 October 2023 (UTC)

What links here

Up until just now Template:WikiProject Cephalopods invoked Module:WikiProject banner with a parameter containing a template, i.e.

|HOOK_ASSESS = {{WPBannerMeta/hooks/bchecklist}}

Template:WikiProject Cephalopods was not listed at Special:WhatLinksHere/Template:WPBannerMeta/hooks/bchecklist, however, a page like Talk:Vampire squid which transcludes Template:WikiProject Cephalopods was listed in WhatLinksHere, which surprised me. Why was the page listed but not the template? — Martin (MSGJ · talk) 07:20, 10 November 2023 (UTC)

The point of WhatLinksHere is so MediaWiki knows what pages need to be regenerated when a template or module is changed. The page Template:WikiProject Cephalopods did not contain anything that would change if the now deleted Template:WPBannerMeta/hooks/bchecklist were changed. However, Talk:Vampire squid transcluded {{WikiProject Cephalopods}} and its wikitext used to transclude {{WPBannerMeta/hooks/bchecklist}}, so Talk:Vampire squid needed to be regenerated when Template:WPBannerMeta/hooks/bchecklist changed. In conclusion, the WhatLinksHere feature is not very helpful for those maintaining templates/modules. Johnuniq (talk) 07:59, 10 November 2023 (UTC)
This is the reason I quite regularly do insource searches when messing around with templates. This has the problem of not detecting redirects, but it is definitely useful in some circumstances. --Trialpears (talk) 08:28, 10 November 2023 (UTC)

Regex question

I am using :gmatch('{{{([^|]+)') to find valid parameters in a template's code. It is not working quite right.

For example the code contains {{{event}}} {{{event-type|edit-a-thon}}} but it seems to be matching with event}}} {{{event-type but not the event-type which I require. — Martin (MSGJ · talk) 13:00, 11 January 2024 (UTC)

[^|]+ will go as far as it can to capture text before running into a pipe, which is why the first capture is so long and contains text from both event and event-type. gmatch then continues from the pipe it got stopped at last time so won't pick event-type up since its beyond it at this point. I'd recommend adding } inside of that negated list, which should prevent it from over-capturing event (and therefore pick up event-type afterwards too). Aidan9382 (talk) 13:31, 11 January 2024 (UTC)
I'm guessing here, but try "-" instead of "+" in the capture. You could also try escaping characters that might have another meaning (e.g.{ and | which would need escaping in regex proper). —  Jts1882 | talk  13:36, 11 January 2024 (UTC)
For some reason I didn't get an edit warning message and missed the reply above. —  Jts1882 | talk  13:38, 11 January 2024 (UTC)
Apparently - is an alias for *. That would not help here — Martin (MSGJ · talk) 14:06, 11 January 2024 (UTC)
Perfect, thanks! — Martin (MSGJ · talk) 14:03, 11 January 2024 (UTC)
Another alternative might be to gmatch the whole parameter and then parse that. In the debug console I get these results using string.match() in place of string.gmatch():
=string.match ('{{{event}}} {{{event-type|edit-a-thon}}}', '{{{([^}]+)}}}')event – this would be the first string.match() result
=string.match ('{{{event-type|edit-a-thon}}}', '{{{([^}]+)}}}')event-type|edit-a-thon – and this would be the second string.match() result
Trappist the monk (talk) 14:39, 11 January 2024 (UTC)
Beware that the parameter default often contains braces in a nested parameter, magic word or template call, e.g. {{{display_text|{{{title}}}}}} or {{{page_name|{{PAGENAME}}}}. In some very clever templates, they even crop up in the parameter name itself. Certes (talk) 14:50, 11 January 2024 (UTC)

How to make multilangual parameters in Module:Navbox

Hello!

I'm translated Navbox module into Kazakh Wikipedia, but have one issue. We've already have a kk:Module:Navbox, but I want to upgrade it. Additionally in the some templates we also used English version of Navbox (english parameters). So I need to add english versions of parameters (Aliases?) to new kk:Module:Шолғы exactly to kk:Module:Шолғы/configuration. I've already ask this question on talk page of Module:Navbox, but nobody replied, that's why I'm writing here Thanks--Amangeldi Mukhamejan (talk) 15:15, 27 October 2023 (UTC)

@Amangeldi Mukhamejan: i only saw this now, sorry about that. i hope it's not too late.
a while ago i wrote a utility module that enables you to use any module from another language with localized parameter names. the idea is simple - i'm sure you won't have any trouble grasping it and figuring out how it's done. see he:יחידה:תרגום יחידה
in a nutshell: for each module you want "translated", you create a "translation" module (in retrospect i guess it could have been a JSON rather than module). then you call the utility module, passing it the target module, the target function, the name of the "translation module", and any parameter you want to pass directly.
the utility module clones the frame (such that the "parent" of the clone is the real parent, not the utility module), it then enriches the "args" and the parent's args with the translated parameters, and then it calls the target module/function with this enriched frame.
note that i said "enriches", not "replace". this means that the caller can use either the original param name _or_ the translated name, which i think is part of your requirements, you can mix and match - some of the parameters can be the translated ones and others can be the original ones
there is some rudimentary documentation as a comment at the top of the module (the doc is not very long, but it's still 50% of the whole thing - the code is short and sweet and pretty easy to understand - no magic. i wrote it per some request on hewiki, and tested it to verify it works, but eventually the requestor decided not to use it, so you can say it's not "tried and tested", only "tested"...
this of course is not specific to "navbox": once you install it, you can use it for any module, at the cost of creating "translation module" for each imported module you want to use with native language parameter names.
if you do decide to use it, i'll be grateful if you can let me know, and of course, if you find bugs let me know too.
peace. קיפודנחש (aka kipod) (talk) 04:24, 26 January 2024 (UTC)