Wikipedia talk:Lua

From Wikipedia, the free encyclopedia
  (Redirected from Wikipedia:Lua requests)
Jump to navigation Jump to search
 WP:Lua
WPtalk:Lua
 Help
 
 To do
 
 Resources
mw:reference manual
 

Template:Calendar - Request to Lua-ize[edit]

This will probably be a Herculean task, but I'm hoping someone can help me with this: Can someone possibly get {{Calendar}} "Lua-ized" via a module at Module:Calendar? Asking since ... something I'm trying to do ran across expensive call template include size issues. So ... I'm really hoping this can be accomplished. Steel1943 (talk) 00:27, 29 June 2019 (UTC)

Not expensive, but rather a template include size problem. You can see the parser profile data for User:Steel1943/sandbox/sandbox2/template by editing that page, and then previewing. At the bottom, click the 'Parser profiling data' link. Profile data are also in the page html source; search for 'NewPP limit report'.
I haven't spent any time with that template but I can probably noodle out how to convert it to a module if no one else does it first.
Trappist the monk (talk) 00:45, 29 June 2019 (UTC)
@Trappist the monk: And there you go; I just learned today that there's more than "expensive" issues when it comes to template calls. If you can figure out how to write that module, it would be greatly appreciated, considering multiple uses of {{Calendar}} in that form could probably benefit many of the discussion boards. Steel1943 (talk) 00:49, 29 June 2019 (UTC)
I wrote Module:Current events calendar back in 2014; that might be of use in converting this template. Even better, we could write a generalised calendar widget module and rewrite Module:Current events calendar to use that. I would advise against naming it Module:Calendar, by the way - it clashes with the module over at Commons, which has caused problems in the past when people try to import modules to other wikis. — Mr. Stradivarius ♪ talk ♪ 09:12, 29 June 2019 (UTC)
So the generalized calendar widget would render a basic month or a basic year calendar? Does the widget define the calendar's style or is that supplied in the call to the widget? Does the call to the widget include a table of links; some specialized prefix / suffix keywords that apply to all dates; links for month / year / next month (year) / previous month (year) / header & footer text (links) / other properties that I haven't thought of yet?
Are there other calendar templates that might take advantage of / influence this widget?
Too bad about Module:Calendar – that is just the right name for a module that implements {{calendar}}. Module:Calendar widget? Continue this discussion there?
Trappist the monk (talk) 10:52, 29 June 2019 (UTC)
Found some other calendar templates in Category:Calendar templates, though from a brief look, it seem it would be hard to make them fit: {{ISOCALENDAR}}, {{Republican Calendar}}, {{List of calendars}} and various Olympic templates at Category:Olympics calendar templates such as {{1952 Winter Olympics calendar}}. --Gonnym (talk) 12:09, 29 June 2019 (UTC)
{{ISOCALENDAR}} has form and styling vaguely similar to {{calendar}} and to Module:Current events calendar so could be a candidate for the widget.
To add to my list above: highlight today's date / some special date / range of dates / all of a specific weekday?
Trappist the monk (talk) 12:50, 29 June 2019 (UTC)
Also: use template styles instead of inline css? If a template using the widget needs special styling, pass in that template's template styles?
Trappist the monk (talk) 13:34, 29 June 2019 (UTC)
I do not see it as problematic that Commons has a module named similar. It's not our problem until such time as something using that module is imported, and when it is, we can maintain a trivial fork here. --Izno (talk) 13:36, 29 June 2019 (UTC)
@Izno: The problem comes when a smaller Wikipedia, let's say Welsh or Azerbaijani, wants to use a template from Commons that calls c:Module:Calendar; and then wants to also use the enwiki template {{Calendar}}. If we use a more qualified name for our module, then they can import everything without having to create a fork on their own language Wiki. My experience is that such forks are rarely trivial for me to do for them in either Welsh or Azerbaijani, or for them to do if they have no Scribunto programmers. --RexxS (talk) 13:49, 29 June 2019 (UTC)
Anyone know how easy it is to rename a page on commons? From the description of that module, c:Module:Convert date seems more correct for it. --Gonnym (talk) 14:16, 29 June 2019 (UTC)
I strongly agree with Izno. Modules should be given names without regard to what is happening on other wikis. Additionally, I don't see the value in having one module having a name that doesn't conflict with Commons when there are already two other modules with conflicting names between the English Wikipedia and commons. * Pppery * ... ... ... 23:19, 29 June 2019 (UTC)

───────────────────────── I've made a start with Module:Calendar widget, Template:Calendar widget and Template:Calendar widget/styles.css. There is some testing of the module at Module talk:Calendar widget/Testing. I threw in a couple of exported functions that check for a leap year and return what day of the week a particular date is. There's virtually no inline styling in the module, but all of the tables, rows, headers and data cells have a class set that can be styled via the template's template styles. I still have to implement most of the parameters available for Template:Calendar, but I'll have another look tomorrow if I get a chance. Please feel free to hack at it if you're interested. Cheers --RexxS (talk) 00:26, 30 June 2019 (UTC)

2000
January
SuMoTuWeThFrSa
      1
2345678
9101112131415
16171819202122
23242526272829
3031     
February
SuMoTuWeThFrSa
  12345
6789101112
13141516171819
20212223242526
272829    
March
SuMoTuWeThFrSa
   1234
567891011
12131415161718
19202122232425
262728293031 
April
SuMoTuWeThFrSa
      1
2345678
9101112131415
16171819202122
23242526272829
30      
May
SuMoTuWeThFrSa
 123456
78910111213
14151617181920
21222324252627
28293031   
June
SuMoTuWeThFrSa
    123
45678910
11121314151617
18192021222324
252627282930 
July
SuMoTuWeThFrSa
      1
2345678
9101112131415
16171819202122
23242526272829
3031     
August
SuMoTuWeThFrSa
  12345
6789101112
13141516171819
20212223242526
2728293031  
September
SuMoTuWeThFrSa
     12
3456789
10111213141516
17181920212223
24252627282930
October
SuMoTuWeThFrSa
1234567
891011121314
15161718192021
22232425262728
293031    
November
SuMoTuWeThFrSa
   1234
567891011
12131415161718
19202122232425
2627282930  
December
SuMoTuWeThFrSa
     12
3456789
10111213141516
17181920212223
24252627282930
31      

So I broke it. I know how it's broken but am at a loss to know why.

I had thought to use the Scribunto HTML library because it seemed to me that support for variations in styling and whatever other sorts of options that might be wanted could more easily handled by that library. I haven't used the HTML library before so my own naivete might be mostly to blame for the broken code.

As you can see the individual monthly calendars aren't top-aligned as they should be. The style is properly included but the <tr> tag that holds it is immediately closed:

<table class="ycal"><tr class="ycalhdr"><th class="ycal" colspan="4">2000</th></tr><tr class="ycal" style="vertical-align:top"></tr><td class="ycal">

For comparison, here is the original (stretched out to make it easier to compare):

<table class="ycal"><tr class="ycalhdr"><th class="ycal" colspan="4>2000</th><tr class="ycal" style="vertical-align:top;"><td class="ycal">

I notice that the original is, I think, missing a </tr> after the <th>...</th> tag.

What did I do wrong? Is it bad that I have only made this change to displayyear() and not to displaymonth()?

The original code remains but has been commented out and there is an mw.log() that dumps the html output to the debug console log.

Trappist the monk (talk) 00:51, 1 July 2019 (UTC)

The vertical-align:top needed to be against the td tag rather than the tr tag. I've also put it in Template:Calendar widget/styles.css instead of in the module code. -- WOSlinker (talk) 05:57, 1 July 2019 (UTC)
Thanks. That appears to fix the issue. But, wait, ... the html is still broken:
<table class="ycal"><tr class="ycalhdr"><th class="ycal" colspan="4">2000</th></tr><tr class="ycal"></tr><td class="ycal">
And shouldn't <tr style="vertical-align:top"> apply to the enclosed <td>...</td> tags?
So I guess my question remains: What am I doing wrong?
Trappist the monk (talk) 10:20, 1 July 2019 (UTC)
Hopefully this change fixes that issue. -- WOSlinker (talk) 10:37, 1 July 2019 (UTC)
Apparently it does:
<table class="ycal"><tr class="ycalhdr"><th class="ycal" colspan="4">2000</th></tr><tr class="ycal"><td class="ycal">
Excellent! But, can you please explain to me why that works?
Trappist the monk (talk) 11:02, 1 July 2019 (UTC)
Before, you were adding both the tr and td tags to the year_cal object (which is the table tag). If you save a reference to the tr tag in a new object then you can add the td tag to that object instead of the year_cal object. -- WOSlinker (talk) 11:10, 1 July 2019 (UTC)
Thank you but, sorry, I'm lost. If the assignment in local year_row = year_cal makes year_row a new object, how does year_cal know anything about what gets added to year_row? This suggests to me that year_row and year_cal are not separate objects but are 'pointers' or 'references' to the same 'thing'. If they are 'pointers' or 'references' then that explains why everything that got added to year_row is present at the end when return tostring (year_cal). But that doesn't explain why it is necessary to indirectly add the <td>...</td> tags via year_row.
Trappist the monk (talk) 11:40, 1 July 2019 (UTC)
Yes, the new variable year_row is a pointer. -- WOSlinker (talk) 12:03, 1 July 2019 (UTC)
Ok, since year_row is a pointer, why is it necessary?
Trappist the monk (talk) 12:25, 1 July 2019 (UTC)
Not really my area of expertise, but I think when you add a new tag against an object, it closes the previously added tag (that was added to that object). -- WOSlinker (talk) 13:03, 1 July 2019 (UTC)
Because calling year_cal:tag('tr') year_cal:tag('td') just adds tags as direct children of year_cal. Calling local year_row = year_cal:tag('tr') year_row:tag('td') adds a tr tag to year_cal, returns it, saves a reference to it in the local variable (because the tag method returns a new object for the tag that was created), and using this reference adds a td tag to it rather than to year_cal. — Eru·tuon 13:36, 1 July 2019 (UTC)
I think that I understand what you wrote but I'm struggling to find the words that describe my continuing confusion.
Trappist the monk (talk) 14:42, 1 July 2019 (UTC)
At about the time that Editor WOSlinker was making this post I was wondering if the right and proper thing to do would be to put the several <td>...</td> tags that are required for each row into :wikitext() because that is how (as I understand it) content is meant to be added to a tag. So I hacked a function that does the necessary work to create <td>...</td> tags and called it from year_cal:wikitext(). It works without confusing indirection.
This is implemented in the current version of the module. Because this widget creates a bunch of tables perhaps it is possible to generalize add_td_tags() so that it can be used more broadly than it is now. I'll think on that.
Trappist the monk (talk) 14:42, 1 July 2019 (UTC)

Is it possible in a template to extract data from a module rather than a function?[edit]

For example, if module was:

local str = "Hello World!"
local p = {["string"] = str};
p.hello = function(frame)
    return str
end

return p

and the template code {{#invoke:moduleName|string}} returned Hello World!. Or do I have to create a function if I want to achieve that? —⁠andrybak (talk) 08:34, 5 July 2019 (UTC)

A module may have a module-wide “global” variables although they are (rather jarringly) declared with local outside functions. The main concern is performance – too much global stuff slows execution down; it is better to resort to require(modulename) in the case where heavy initialized data are desirable. Incnis Mrsi (talk) 09:56, 5 July 2019 (UTC)
The question concerns whether X in {{#invoke:moduleName|X}} has to be a function name, or whether it could be a code (such as "string") to get the code's value (such as "Hello World!"). The answer is yes it can be a code, but it's pretty ugly and involves setting a metatable on p such that X is interpreted at runtime. A lot less hair would be lost if the call were {{#invoke:moduleName|get|X}} where the function get returns the value for X. See Module:Data for how magic metatable code can be written. Johnuniq (talk) 10:43, 5 July 2019 (UTC)

Question from a newbie[edit]

Hello, I have few connoissances into Lua. I have (one) (or multiple words) into a given string. Example : <CDG LAX JFK> (string without the < and the >) I would need this string transformed into %22CDG%20LAX%20JFK%22 so that this being understandable by a sparql query. I have written a short code but it doesn't come the fashion I need. Any tip would be greatly appreciated. --Bouzinac (talk) 20:16, 23 July 2019 (UTC)

Can the URI library help you here? --Gonnym (talk) 20:18, 23 July 2019 (UTC)
Thanks. I was building this function
local p = {}
s=frame.args[1]
function p.recode(frame) 
    return "%22".. s:gsub(" ","%20").. "%22"
end
return p
Where am I wrong ?
OK, got it with
local p = {}

function p.recode(frame) 
	return "%22" .. mw.uri.encode(frame.args[1],"PATH") ..  "%22"
end
return p
 :) --Bouzinac (talk) 20:43, 23 July 2019 (UTC)
No, it does not work when multiples code, works only when one code. I need a transformation being string other_string other_string be "string" "other_string" "other_string"
and then be urlencoded. Bouzinac (talk) 20:52, 23 July 2019 (UTC)
If I understand you right, maybe something like this would work:
local function transform(s)
	return mw.uri.encode(s:gsub("%S+", '"%1"'), "PATH")
end

function p.transform(frame)
	return transform(frame.args[1])
end
It encloses sequences of non-ASCII-whitespace characters in quotes and then percent-encodes the string. — Eru·tuon 21:13, 23 July 2019 (UTC)
That's exactly what I wished. Many thanks --Bouzinac (talk) 21:18, 23 July 2019 (UTC)

mw.ext.ParserFunctions.expr[edit]

I'm trying to use the ParserFunctions library in lua for it's trunc() calculation, but Help:Extension:ParserFunctions has no documentation at all how its used other than mw.ext.ParserFunctions.expr. The most I was able to get is mw.ext.ParserFunctions.expr("trunc", value) but that gives me the error "Lua error: Expression error: Missing operand for trunc..". Any ideas? --Gonnym (talk) 07:43, 24 July 2019 (UTC)

Gonnym, i've made a task of the fact that this library is undocumented. phab:T228840TheDJ (talkcontribs) 08:52, 24 July 2019 (UTC)
Thanks! --Gonnym (talk) 18:29, 24 July 2019 (UTC)
Try this (untested).
local success, result = pcall(mw.ext.ParserFunctions.expr, 'trunc 1234.5678')
if success then
    -- result is the result
else
    -- result is error text
end
Johnuniq (talk) 08:16, 24 July 2019 (UTC)
That seems to work although I have no idea why, as mw.ext.ParserFunctions.expr('trunc 1234.5678') doesn't. --Gonnym (talk) 18:29, 24 July 2019 (UTC)
@Gonnym: are you sure? i didn't create a module to test it, but it did return 1234 in scribuntu debug console (open any module for edit, and type "=mw.ext.ParserFunctions.expr('trunc 1234.5678')" <Enter> in the debug console). peace - קיפודנחש (aka kipod) (talk) 18:53, 24 July 2019 (UTC)
Well, now it does work. No idea what I did differently before. I blame the hour. Also, thanks :)--Gonnym (talk) 19:23, 24 July 2019 (UTC)
oh, and the most intriguing question: why would anyone even want to call "mw.ext.ParserFunctions.expr" if what you want to do is "trunc"? why not ask lua directly?
local input = 1234.5678
local truncated = math.floor(input) -- returns the same as mw.ext.ParserFunctions.expr('trunc ' .. input)
input = '1234.5678' -- works for strings, too:
truncated = math.floor(input) -- still 1234: i guess math.floor is nice enough, and calls tonumber() for you, or something. JS behave similarly
-- math.floor will throw if the parameter is not "numberable", e.g. "bla", '', or nil. you can use pcall, or test directly:
local num = tonumber(input)
if num then -- safe: in lua, 0 evaluates to true
    truncated = math.floor(num)
else
-- do some error handling
end
i can't imagine what do you gain by calling mw.ext.ParserFunctions.expr, if what you want to do is trunc, unless the parameter passed to the template _is_ trunc 1234.5678 or or trunc(1234.5678). this looks a bit bizarre (why would the editor pass something like this as a parameter?), but i guess it's possible. peace - קיפודנחש (aka kipod) (talk) 19:34, 24 July 2019 (UTC)
I'm trying to convert a set of templates to lua, so the first step I was trying to do is just understand the code flow and get a simple version working. That template used the trunc function which was why I wanted that. I didn't spend time debugging all scenarios to see if it did anything else. I completely agree with you though, that using your suggested code would be a much better end-result. --Gonnym (talk) 20:10, 24 July 2019 (UTC)
I have converted a couple of complex templates by writing the logic in pseudocode, being careful to include all the tricky conditions that apply to template wikitext (like what #if really does). After I've got the pseudocode, I convert that to Lua and hope that testcases will detect problems. Some functions in Module:Math might be useful. Johnuniq (talk) 00:13, 25 July 2019 (UTC)

Arithmetic expressions as strings[edit]

I have an array of arithmetic expressions as strings and I need to do a calculation with an x value for the relevant one, however it can't do that with an arithmetic expression as a string. I'd like to avoid needing to do this as an if/else. Any ideas? Code below:

local function main(value1, value2)
	local arithmeticExpressionList = {
		[1] = " % 2 + 4",
		[4] = " / 2 % 2 + 2",
		[6] = " / 4 % 2 + 5",
		[9] = " / 8 % 2 + 5",
		[12] = " / 16 % 2 + 3",
		[14] = " / 32 % 2 + 8",
		[17] = " / 64 % 2 + 6"
	}

	local arithmeticExpression = arithmeticExpressionList[value1]
	if (arithmeticExpression) then
		value = value2 .. arithmeticExpression
		return value
	end
end

--Gonnym (talk) 06:51, 25 July 2019 (UTC)

A simpler example with the expected result would be helpful (or use this example if you want to show its evaluation). I can't tell if the items should be concatenated and then evaluated or what. And % is remainder? Essentially you have to write your own expression parser (which I have done for a special purpose, but definitely not recommended!), or use mw.ext.ParserFunctions.expr from the previous section. Johnuniq (talk) 07:31, 25 July 2019 (UTC)
For a given value1 of 1 and a value2 of 7: value = value2 .. arithmeticExpression should be the same result as value = 7 % 2 + 4. % is Modulo operation. --Gonnym (talk) 07:36, 25 July 2019 (UTC)
Thanks for the tip about using mw.ext.ParserFunctions.expr, that does work (with a small change from "%" to "mod"). --Gonnym (talk) 07:44, 25 July 2019 (UTC)
Works, but producers different results for some values. mw.ext.ParserFunctions.expr(48.. arithmeticExpressionList[17])) results in 6, while 48 / 64 % 2 + 6 results in 6.75. That said, the template that I'm working from also gives 6, so mw.ext.ParserFunctions.expr is at least consistent with that and produces the same results. --Gonnym (talk) 08:10, 25 July 2019 (UTC)
Lua's % is more like ParserFunctions.expr's fmod, FYI. At least for positive numbers. Anomie 13:28, 25 July 2019 (UTC)
Do the arithmetic expressions actually have to be strings? If not, this should work:
local function main(value1, value2)
	local arithmeticExpressionList = {
		[1] = function ( x ) return x % 2 + 4 end,
		[4] = function ( x ) return x / 2 % 2 + 2 end,
		[6] = function ( x ) return x / 4 % 2 + 5 end,
		[9] = function ( x ) return x / 8 % 2 + 5 end,
		[12] = function ( x ) return x / 16 % 2 + 3 end,
		[14] = function ( x ) return x / 32 % 2 + 8 end,
		[17] = function ( x ) return x / 64 % 2 + 6 end
	}

	local arithmeticExpression = arithmeticExpressionList[value1]
	if (arithmeticExpression) then
		return arithmeticExpression( value2 )
	end
end
Anomie 13:28, 25 July 2019 (UTC)


Lua pattern question[edit]

Hey, I can't see how to get an exact match. I am using [Cc]hess in a template, looking to get back only the full-word matches of " Chess " and " chess ", but I of course also get "duchess", "duchesses", "Chessie", etc. What pattern code returns only the selected characters when they are surrounded by spaces, and not part of a larger word? Thanks in advance. UnitedStatesian (talk) 12:53, 20 August 2019 (UTC)

try: %f[%a]([Cc]hess)%f[%A]
Trappist the monk (talk) 13:05, 20 August 2019 (UTC)
Thanks TTM, that worked perfectly. You are the MAN! UnitedStatesian (talk) 14:00, 20 August 2019 (UTC)
@Trappist the monk: for my own edification, why is the first %a lower case and the second %A uppercase? Does it matter? UnitedStatesian (talk) 03:49, 23 August 2019 (UTC)
Yes, it matters. Search for "frontier" at mw:Extension:Scribunto/Lua reference manual and see lua-users. %a matches all letters, while %A does the opposite (it matches all non-letters). Johnuniq (talk) 04:05, 23 August 2019 (UTC)
Please excuse the typo fix, Johnuniq, the reference manual is on mediawiki, not meta (I make that mistake myself all the time).
@UnitedStatesian: The frontier pattern "%f[%a]" matches the transition from non-letters to letters, so "%f[%a]chess" would match "chess" at the beginning of a word (including the beginning of a string). The frontier pattern "%f[%A]" matches the transition from letters to non-letters, so "chess&f[%A]" would match "chess" at the end of a word (including the end of a string). The pattern that Trappist gave you uses both frontier matches to isolate the word alone as a match. HTH --RexxS (talk) 14:01, 23 August 2019 (UTC)
Thanks, both! UnitedStatesian (talk) 14:13, 23 August 2019 (UTC)