Wikipedia:Lua
Wikipedia-navnerom | |||
---|---|---|---|
Grunnleggende navnerom |
Tilhørende diskusjonsnavnerom | ||
0 | (Hoved) | Diskusjon | 1 |
2 | Bruker | Brukerdiskusjon | 3 |
4 | Wikipedia | Wikipedia-diskusjon | 5 |
6 | Fil | Fildiskusjon | 7 |
8 | MediaWiki | MediaWiki-diskusjon | 9 |
10 | Mal | Maldiskusjon | 11 |
12 | Hjelp | Hjelpdiskusjon | 13 |
14 | Kategori | Kategoridiskusjon | 15 |
100 | Portal | Portaldiskusjon | 101 |
828 | Modul | Moduldiskusjon | 829 |
Virtuelle navnerom | |||
-1 | Spesial | ||
-2 | Media | ||
Lua er et programmeringsspråk som nå er tilgjengelig på Wikipedia på norsk bokmål og riksmål via programtillegget Scribunto i MediaWiki. Luakode kan nå bakes inn i Wikipedia-maler ved å bruke «{{#invoke:}}»-funksjonen.
Lua(kilde)koden lagres i sider som kalles moduler, som ligger i navnerommet Modul (for eksempel Modul:Lua banner). En Lua-modul kalles normalt fra en malside ved hjelp av en {{#invoke:}}
-funksjon, for eksempel {{#invoke:Lua banner|main}}
.
Hovedformålet med denne siden er å hjelpe de som vil kode en Lua-modul for Wikipedia, ved å gi tips, retningslinjer og kontakter med andre som koder Lua-moduler.
Lua i Wikipedia
redigerEt Hello World-eksempel er Modul:HelloWorld:
mitt_objekt = {}; -- Alle Lua-moduler i Wikipedia må begynne med å definere en variabel som har
-- eksternt tilgjengelige funksjoner. De kan ha valgfrie navn og kan også inneholde data.
mitt_objekt.hei = function( frame ) -- Legg til en funksjon til variabelen. Disse er mulige å kalle fra
-- Wikipedia med #invoke. «frame» inneholder dataen som Wikipedia
-- sender til denne funksjonen når den kalles.
local str = "Hello World!" -- Angi en lokal variabel, og gi den data.
return str -- Avslutt denne funksjonen og send data i «str» tilbake til Wikipedia. Wikipedia.
-- «print»-funksjonen er ikke tillatt, så utskriving gjøres ved å sende
-- data tilbake på denne måten.
end -- Slutten på funktionen.
return mitt_objekt -- Alle moduler avsluttes med å sende variabelen tilbake med disse funksjonene
-- til Wikipedia.
-- Vi kan nå bruke denne modulen med {{#invoke: HelloWorld | hei }}.
-- #invoke-kommandoen begynner med modulens navn, i dette tilfellet «HelloWorld»,
-- deretter følger en av modulens funksjoner, i dette tilfellet «hei».
For en mer detaljert beskrivelse om bruk av Lua på Wikipedia, se mw:Extension:Scribunto/Lua reference manual (engelsk).
Best practice
redigerDet finnes noen best practice som er allment gode, uten at de har blitt retningslinje på dette prosjektet.
No globals
redigerForsøk alltid å unngå forsøpling av det globale navnerommet, det vil si bruk local
og do … end
for å skape lokal kontekst for variabler og funksjoner. For å vise klart og tydelig at en modul ikke forurenser det globale navnerommet kan require('strict')
legges i toppen av modulen. Alle forsøk på å legge til nye globale oppføringer vil deretter gi en feilmelding. I noen tilfeller er det nødvendig å lage globale funksjoner, vær da tydelig på hva som legges til og hvorfor.
Dokumentasjon
redigerDokumenter modulens generelle egenskaper. Disse legges på en underside «Module:navn/dok». Disse skrives på et fellesspråk (typisk engelsk) eller på lokalt språk (for oss norsk). Vær nøye på å dokumentere funksjoner, gjerne med med JDoc-style, og ikke glem å ta med konfigurasjonsvariable. Hvis modulen har utelatte kodesekvenser så merk disse med -- @todo
slik at de kan finnes av andre. Husk at vi er et sammarbeidsprosjekt!
Bruk tester
redigerSett opp tester for modulen. Disse legges på en underside «Module:navn/testtilfeller». Det er tre biblioteker i bruk med litt forskjellig tilnærming. Det er viktigere at det settes opp tester enn hvilken av bibliotekene som brukes. Tester bør dekke mest mulig av modulens funksjonalitet, men det finnes for øyeblikket ingen biblioteker som kan profilere et helt bibliotek. Det finnes derimot et bibliotek for å gjøre timing av enkeltfunksjoner (w:en:Module:Timing).
Informer om scripting
redigerDenne malen benytter seg av Lua: |
Legg til malen {{Lua}} lengst opp på malsiden for alle maler som bruker Lua. Dette for å hjelpe de som ikke kjenner til Lua, og for å få en oversikt over hvilke maler som bruker Lua. Malen brukes slik: {{Lua|Modul:Modulnavn}}
. Et kall {{Lua|Modul:HelloWorld}}
er vist på høyre side.
Bruk biblioteksfunksjonene
redigerBruk de felles standardbibliotekene der det er mulig, men ha i bakhodet at det i noen tilfeller kan være fornuftig å reimplementere funksjonalitet. Spesielt hvis det gir enklere og mindre kode, og modulen er svært mye brukt kan det være gunstig å unngå import av store biblioteker. Vær oppmerksom på kodekvalitet, og at denne kan være bedre i de større og mer gjennomarbeidde modulene. Det finnes to eksterne biblioteker som bør vurderes, et for strengmanipulering (Allen) og et for tabellmanipulering (Moses).
Separation of concerns
redigerHusk på separation of concerns. Spesielt gjelder dette separasjon av meldinger fra resten av koden, og ikke minst anbefales det at mekanismene for internasjonalisering/lokalisering brukes. Det finnes et standardbibliotek for håndtering av språkspesifikke forhold (Language library) og et for håndtering av meldinger (Message library). Det bør brukes fallbackmekanismer for å fange opp at meldinger kan mangle i de enkelte språkene.
Lokalisering
redigerDet er alltid lurt å skille ut lokalisering av de enkelte språkene på egne sider. For å gjøre det enkelt å oversette fra et språk til et annet kan det lages en mal ala w:en:Template:Localization subpage. Denne kan settes på dokumentasjonssiden for en lokalisering og forenkler kontroll av samsvar mellom språkene. Et eksempel er denne diffen mellom to språkversjoner. For å gjøre det enklere for diff-mekanismen å synkronisere mellom språkene, det er ofte mye forskjeller mellom dem, så kan det settes inn noen kommentarer som sier hva de enkelte blokkene omhandler. Disse kommentarene må være på samme språk.
MVC
redigerHvis det modelleres etter paradigmet Model–view–controller (MVC) så er Lua-script delvis i «model» og «view», men er i liten grad i «controller». Den siste er i hovedsak drevet av Javascript i nettleseren. I noen grad kan Lua bli del av controlleren, men da via serverens API.
Tenk sikkerhet
redigerDet er begrenset hvor det kan oppstå sikkerhetsproblemer, men i hovedsak gjelder de samme reglene i Lua som i andre språk – filtrer input og escape output. Mesteparten av input når Lua via serverens normale mekanismer og er allerede filtrert. Det som genereres av Lua-scriptene kan imidlertid omgå mekanismene for automatisk escaping via metoder for rå html-kode, og kan dermed representere en sikkerhetsrisiko. Hvis du bruker rå html-kode så må output escapes eksplisitt. Vær påpasselig der strenger konkateneres, alle strenger må escapes skal resultatet være trygt. Bruk standardbiblioteket for html der det er mulig (HTML library), og returner wikitekst gjennom metoden for dette. Strenger er trygge hvis de returneres uten å merke de som rå strenger, da vil de bli prosessert av mediawiki som all annen wikitekst.
Begrensninger i Wikipedia
rediger- Lua-koden kjøres bare når en side tolkes – det vil si når en side lagres, forhåndsvises, etc. – og Lua kan bare få inndata som tekststrenger sendt med
{{#invoke:}}
og som er mulig å hente fra frame.expandTemplate, frame.preprocess, osv. - Wikitekst som sendes ut fra Lua blir ikke bearbeidet, så i maler og all annen transkludering vil teksten vises som den er.
- Lenker av typen [[Wikipedia:Hjelp|]] fungerer ikke som utdata fra Lua – de må skrives eksplisitt som [[Wikipedia:Hjelp|Hjelp]].
- Det er heller ingen annen behandling av innholdet, for eksempel å erstatte
~~~~
med signaturer. - Lua-koden på en side er begrenset til maks 10 sekunder CPU-tid på serveren.
- For en delvis liste av begrensinger, se mw:Extension:Scribunto/Lua reference manual#Differences from standard Lua.
Din sandkasse
redigerHvis du kun skal sjekke en enkelt side så er feltet for forhåndsvisning på redigeringssiden tilstrekkelig. Hvis du derimot må overstyre flere maler og moduler så må du bruke Special:TemplateSandbox og plassere alle sider under en felles rot. Alle sider under denne roten vil overstyre sider i andre navnerom for fremvisning av artikkelen du oppgir for forhåndsvisning. Du kan også forhåndsvise en spesifikk versjon eller en gitt wikitekst.
Hvis du må gjøre endringer på en side for å vise frem en spesifikk funksjon eller formatering, så kan du lagre denne versjonen og så rulle tilbake til en fungerende versjon. Da har du en revisjon du kan oppgi i Special:TemplateSandbox som utgangspunkt for din modifisering.
Når du tester ut sider i sandkasser så er det noen plasseringer av disse sidene som er blitt vanlige.
Hvis du skriver på din egen versjon av en modul så kan du bruke Spesial:Diff for å sammenligne endringene i din egen modul med utgangspunktet. Konfigurering av lenkingen er avhengig av hvordan du har satt opp din sandkasse, men typisk må du lage en lenke ala
[[Special:Diff/{{REVISIONID:<sideA>}}/{{REVISIONID:sideB}}]]
Hvor ene siden er i din sandkasse og andre siden er modulen som er utgangspunkt for dine endringer.
Privat sandkasse
redigerHvis du ønsker å bytte ut wikikoden med Lua i en mye brukt mal eller modul, og det kun er du selv som er involvert i prosjektet, så kan det være en fordel å prøve seg frem i en privat «sandkasse». Denne kan du opprette som en egen underside under din egen bruker, typisk noe ala (erstatt teksten mellom < > med passende tekst)
Bruker:<Ditt brukernavn>/sandkasse/Modul:<Navnet på din modul>
Merk at du må bruke den lokale formen av navnerom, det vil si «Modul» og ikke «Module» eller «modul». Som oftest må du også endre require
slik at koden henter inn riktige biblioteker.
Bruk Special:Prefiksindeks på siden «Bruker:<Ditt brukernavn>/sandkasse/» for en liste over alle dine sider som bruker dette navneskjemaet. Roten du oppgir til TemplateSandbox i dette tilfellet er «Bruker:<Ditt brukernavn>/sandkasse».
Så lenge du gjør endringer på sider i ditt eget brukerrom er det få som vil ha innvendinger. Det er også en ulempe hvis du ønsker tilbakemeldinger.
Felles sandkasse A
redigerHvis det er flere som er involvert i prosjektet, og dere kun trenger en sandkasse, så kan det være lurt å bruke siden som det lenkes til som standard. Mange moduler legger opp til at sandkassen på formen (erstatt teksten mellom < > med passende tekst)
Modul:<modul-navnet>/sandkasse
Bruk Special:Prefiksindeks på siden «Modul:<modul-navnet>/sandkasse» for en liste over alle sider som bruker dette navneskjemaet. Roten du oppgir til TemplateSandbox i dette tilfellet er «Modul:<modul-navnet>». (Er lenka feil, dette impliserer at navnet ikke er tilgjengelig for overstyring?)
Vanligvis blir formen kun brukt for å redigere modulen(?).
Fordelen med denne formen er at andre brukere lett finner frem, og dermed får du tilbakemelding på endringer. Ulempen er at du kan få mye tilbakemeldinger, og de er ikke alltid like velformulert.
Felles sandkasse B
redigerHvis du vil ha en halvåpen sandkasse, eller det er flere som skriver på en mal eller modul som er litt forskjellige, så kan du opprette en sandkasse på dette formatet (erstatt teksten mellom < > med passende tekst)
Modul:Sandkasse/<Ditt brukernavn>/Modul:<Navnet på din modul>
Også her må en bruke den lokale formen av navnerom, det vil si «Modul» og ikke «Module» eller «modul», og endre require
slik at koden henter inn riktige biblioteker.
Bruk Special:Prefiksindeks/Modul:Sandkasse for en liste over alle sandkasser som bruker dette navneskjemaet. Roten du oppgir til TemplateSandbox i dette tilfellet er «Modul:Sandkasse/Modul:<Ditt brukernavn».
Modulen «Sandkasse» finnes ikke, det er kun en overenskomst at den brukes som rot i dette navneskjemaet.
Fordelen med denne formen er at andre brukere lett finner frem, slik at du får tilbakemeldinger, og at det er lett å skrive på flere moduler samtidig.
Testing av Lua-moduler/funksjoner
redigerLua er et programmeringsspråk, og som alle slike er det mulig å gjøre feil. Under selve utviklingen av en modul er det viktig å teste på en effektiv måte, ikke minst for å unngå å introdusere feil i kode en har skrevet tidligere. Wikipedia er et stort kjøremiljø for kode, mye større enn det som er vanlig på andre nettstedere. Det er derfor overordentelig viktig at alt fortsetter å fungere som forventet etter endringer. Det er for å forenkle slik testing at det er laget egne testbiblioteker.
Generelt så blir testing gjort etter tre forskjellige paradigmer; enhetstesting, testdrevet utvikling, og oppførelsdrevet utvikling. Dels kan en se på disse tre som separate paradigmer, men de er nok like mye forskjellig tilnærming til hvordan en gjør testing.
Enhetstesting
redigerEnhetstesting er helt konkret hvordan en tester en enhet, ofte ved å injisere forskjellige former for «spioner» i den kjørbare koden. Som oftest er enhetstesting tett knyttet til en bestemt implementasjon av en modul, og hvis en bytter modulen så bytter en også testsettet. Ofte er koblingen så tett at testsettet kan låse implementasjonen til en gitt løsning.
Testdrevet utvikling
redigerTestdrevet utvikling går ut på at en definerer kontrakten for hvordan en metode skal oppføre seg før en skriver selve koden. Dette er en god løsning der en har en klar kravspesifikasjon på forhånd, eller hvor en kan utlede en slik kravspesifikaasjon. Problemet med dette er at når en skal løse et problem så er kravspesifikasjonen utenfor det en er mest fokusert på, dermed blir testspesifikkasjonen ufullstendig.
Oppførselsdrevet utvikling
redigerOppførelsdrevet utvikling er tettere på agile development, men med noen føringer på hvordan løsningen beskrives. Ved å bruke et nokså enkelt språk så tvinges en til å konkretisere nødvendig funksjonalitet og hva den skal utføre. Tradisjonell testing blir ofte gjort i etterkant, selv om dette er suboptimalt, mens ved oppførselsdrevet utvikling så defineres testene som en integrert del av kravspesifikasjonen.
Pragmatisk tilnærming
redigerDet vi gjør i Wikipedia er veldig ofte at vi lager en første implementasjon, og deretter legger til tester for å bekrefte (verifisere) våre antakelser om koden. Etter hvert legges det til mer kode, og det legges til mer tester. Slik itererer vi oss fremover. Vi har ofte ikke en helt klar formening om hva vi gjør først, testing eller utvikling, og det finnes ingen klar bestiller av funksjonaliteten. Ulempen med dette er at vi kan ende opp med metoder og tester som ikke er optimale i fordi vi ikke har en klar kravspesifikasjon.
Tilgjengelige bibliotek
redigerHvordan vi tester er mer et metodevalg enn et valg av testbibliotek. Noen biblioteker lener seg litt mer til ett av paradigmene enn til de andre, men de som er tilgjengelig kan brukes for alle de tre skisserte. Modul:UnitTests er tett på overfladisk enhetstesting, hvor det essensielle er å ha noen primitiver for å teste likhet mellom input og output til og fra funksjoner. Modul:ScribuntoUnit er nok noe tettere på testdrevet utvikling, hvor en setter opp et testharness og itererer seg frem i vekselvirkning med koden som testes. Modul:BDD (under utvikling) har mest til felles med oppførselsdrevet utvikling og bruker elementer fra domenedrevet design. Denne modulen har noe støtte for tettere iterasjoner med koden som utvikles enn de to foregående modulene.
Modulene TestUnits er importert fra enwiki, mens ScribuntoUnit opprinnelig kommer fra huwiki. Modulen BDD er lokal her på nowiki. Testtilfellene skrives på en underside «Moduldiskusjon:modulename/testtilfeller» hvor modulename er modulen som testes. Resultatene vises på undersidens diskusjonsside, «Modul:modulename/testtilfeller», eller ved integrasjon i testmodulens dokumentasjon, eller ved å bruke tilleggsfunksjonen Hjelp:Integrert testing. Denne viser testene på samme side som modulen når den åpnes for redigering.
Kategoriserte testresultat
rediger- Merk at koden for å kategorisere moduler på bakgrunn av feilede tester er fjernet.
Det er to typer kategoriserte resultat som følge av feil. En type feil gir kategorisering i sider med skriptfeil, og kategorisering utløses som følge av inkludering av script med feil fra kompilering eller kjøremiljøet. Feilen kan skje i selve kallet på siden, eller i selve modulen, eller i en inkludert modul. Disse feilene vil vanligvis bli synlig med en stor rød feilmelding på siden. For å påvise hvor feilen er så klikker en på den røde lenken og får da opp ytterligere informasjon, med hvor feilen oppstod og linjenummer. I noen få tilfeller blir det ikke påvist noen klar og entydig kilde, og da er ofte feilen i forbindelse med invoke eller oversettelsen til modulens eksporterte tabell.
En annen type kategorisering plasserer modulene i category-all-tests, og underkategoriene category-good-tests og category-failed-tests. Moduler kategorisert i category-failed-tests er de som av noen grunn har tester som feiler. Kategorisering av modulene skjer via en eksportert metode fra testmodulene. Denne metoden legger til kategorier for moduler med testtilfeller, og hvorvidt resultatene er gode eller feiler. Det er ingen ytterligere detaljering utover kategorisering.
De andre språkprosjektene bruker ikke slik kategorisering, så skal modulene oppdateres så må ekstra kode legges til modulene. For å få kategorisering til å fungere er det nødvendig å gjøre en mindre endring i hvordan require skrives. Tidligere er den gjerne skrevet require('Module:modulename')
, men for å få installert de ekstra metodene må det legges til et kall på resultatet fra require, typisk skrives dette som require 'Module:modulename'()
.
Se også
rediger- Spesial:Prefiksindeks/MediaWiki:Scribunto (alle lokale systemmeldinger for Scribunto-utvidelsen)
- Spesial:Alle systembeskjeder (alle definerte systemmeldinger for Scribunto-utvidelsen)
- Alle moduler på Wikipedia på norsk bokmål og riksmål
- Brad Jorsch-presentasjon av et enkelt eksempel for hvordan man konverterer en wikitekst-mal til en Lua-modul (pdf på engelsk)