Op openSUSE 15.5 lukte het niet om git versie van Gambas 3.19.90 te compileren.
Wat wel lukte op Tumbleweed, lukt niet op openSUSE 15.5.
In de repositories is geen Gambas3 voor 15.5 beschikbaar, dus het wordt zoeken naar een andere oplossing…
(zie ook gambas3 verdwenen na update openSUSE)
Continue reading
Project open geeft foutmelding
Ik kan mijn project niet openen, de foutmelding zegt iets over bepaalde forms die niet in mijn project zitten, iets met FWelcome en zo.
De oorzaak bleek een fout in het .project
bestand, die veroorzaakt was door een git merge conflict. Er stond code in met === enz, eens die verwijderd werkte het terug.
De Gambas IDE foutmelding had dus iets moeten zijn als “invalid .project file”.
gambas3 verdwenen na update openSUSE
Gambas3 is verdwenen …
– uit de repo’s van opensuse Tumbleweed
– uit het development menu na de zypper dup
update van openSUSE Tumbleweed;
Gambas3-ide komt niet voor bij software, maar de andere onderdelen als de runtime zijn wel (nog) aanwezig, bv:
gambas3-runtime - Gambas runtime interpreter
Version:
3.19.3-1.2
Build Time:
Wed 03 Jul 2024 01:46:34 PM CEST
Install Time:
Fri 05 Jul 2024 05:25:44 PM CEST
License:
GPL-2.0-or-later
Installed Size:
2.2 MiB
Download Size:
0 B
Distribution:
home:munix9 / openSUSE_Tumbleweed
Vendor:
obs://build.opensuse.org/home:munix9
Packager:Architecture:
x86_64
Build Host:
reproducible
URL:
https://gambas.sourceforge.net/
Source Package:
gambas3-3.19.3-1.2
Media No.:
0
Authors:
Andere versies/repo’s
In de education repository is gambas 3.14 aanwezig, dus die repo aanzetten zou een mogelijkheid kunnen zijn als een oudere versie volstaat.
In de home:Henry15ea Community is versie 3.18.1 aanwezig.
Andere openSUSE versies
In openSUSE 15.5 waren de updates gebeurd tot 2024-07-28
. Nu in Yast, Software Management staat alles van Gambas3 “rood”; ik heb de hele gambas3 lijst van programma’s “protected” gezet.
OpenSUSE 15.5: Gambas3 v 3.19.3
In openSUSE 15.4 in Yast staat alles van Gambas3, versie 3.18.4 “rood”.
Gambas3 is niet meer terug te vinden in de repo waar het uit geïnstalleerd is (obs:/:build.opensuse.org/home:munix) Zie ook software.opensuse.org
Over het verdwijnen uit de munix repo is nergens iets te vinden op dit moment.
Het heeft blijkbaar met openSUSE (of de – versie) te maken …
Op de website van gambas is niets abnormaals gemeld.
Vertrek van de bron
Mogelijkheid: de broncode van gambas afhalen en zelf compileren tot werkend programma.
Dat lukte op deze manier nog met versie 3.19.90 (20-8-2024).
Listbox_Click, Message.Question, Listbox.Remove
OpenSUSE-KDE-Plasma Gambas 3.19.3 qt5
Een eigenaardig feonomeen: ik laat de gebruiker op de listbox klikken, waarop gevraagd wordt of hij de betreffende listbox lijn (aangeduid door Listbox.index) wil verwijderen. Zo ja, verwijder ik die met Listbox.Remove(Listbox.Index).
Mijn voorbeeld: de listbox (Mode: Single) bevat 1 lijn. Ik klik op knop 1.
Code:
Public Sub lsbxError_Click() Dim i As Integer ' i = Message.Question(lsbxError.Index & ": " & lsbxError.Text, "Clear", "Clear All", "Cancel") Debug i Select i Case 1 lsbxError.Remove(lsbxError.Index) Case 2 lsbxError.Clear Case 3 ' else do nothing End Select ' End
Na het verwijderen van de lijn krijg ik een nieuwe vraag met een lege tekst en als index -1. Als je nog eens op Clear klikt, krijg je een foutmelding Out of bounds
.. op de lijn van de Remove; het gaat blijkbaar over de index.
Ik merk op (bij meer elementen) dat de listbox na het verwijderen een ander item selecteert (zonder dat ik dat expliciet vraag), dat ik dan ook niet meer kan kiezen voor verwijderen.
Ik kan de fout blijkbaar vermijden door een “unselect” toe te voegen:
Public Sub lsbxError_Click() Dim i As Integer ' i = Message.Question(lsbxError.Index & ": " & lsbxError.Text, "Clear", "Clear All", "Cancel") Debug i Select i Case 1 lsbxError.Remove(lsbxError.Index) lsbxError.UnselectAll() Case 2 lsbxError.Clear Case 3 ' else do nothing End Select ' End
en de “index” fout kan ik vermijden door op voorhand een voorwaarde toe te voegen:
Public Sub lsbxLog_Click() Dim i As Integer Debug lsbxLog.Index If lsbxLog.Index >= 0 Then i = Message.Question(lsbxLog.Text, "Clear", "Clear All", "Cancel") Select i Case 1 lsbxLog.Remove(lsbxLog.Index) lsbxLog.UnselectAll() Case 2 lsbxLog.Clear Case Else ' else do nothing End Select Endif End
Raspbian 11: $EDITOR gezocht
Editor of $EDITOR?
Een van de eerste dingen die opvallen na installatie van Gambas3 op de Raspberry Pi met OS Raspbian GNU/Linux 11 is dat Gambas naar de “Editor” vraagt bij het openen van een bestaand (git-)project:
Please set the $EDITOR environment variable with your favorite graphical text editor. Some version control commands need it
Dit heb ik opgelost door de volgende lijn toe te voegen aan /etc/profile
.
export EDITOR=/usr/bin/mcedit
Select-editor
De .bashrc
oplossing zoals andere Linux distributies (bv OpenSUSE Gambas opstart set $Editor) werkt hier niet op Raspbian.
De Raspberry Pi heeft zijn eigen tool voor het instellen van de editor (waarvan het resultaat niet herkend werd door Gambas), het commando
select-editor
.
Daarna krijg je een keuzemenu met genummerde mogelijkheden, en kan je met een cijfer je keuze maken, bv 1. Nano.
Als je zelf bv al midnight commander geïnstalleerd had, komt mcedit
ook voor in de keuzelijst.
Select-editor toont helaas niet wat de huidige keuze is.
Na de keuze zet select-editor een verborgen bestand .selected_editor
in je home direoctory, met daarin
SELECTED_EDITOR="/usr/bin/mcedit"
Ik vermoed dat het bij de volgende start/login gelezen wordt.
Of toch niet? Maar Gambas blijft de $EDITOR variabele vragen, zelfs na de volgende login. Ik weet dat de keuze aktief is door een test metcrontab -e
. Het bestand ~/.bashrc bestaat ook hier, en ik voeg toe:EXPORT EDITOR=/usr/bin/mcedit
maar op geen enkele manier (met aanhalingstekens, zonder, met $, zonder..) werkt dat. (m.a.w. Gambas3 blijft de vraag stellen). Ik probeer de volgende lijn toe te voegen aan/etc/profile
:export EDITOR=/usr/bin/mcedit
(sudo nodig). Na herstarten op de commandlineecho $EDITOR
/usr/bin/mcedit Deze keer ok!
Fout in Library
Door een fout in een library kreeg ik in mijn applicatie (het programma dat die library gebruikte) fouten die ik niet begreep.
Library:
ExampleObject
– id
– SomeExternalId
– otherdata
In de library zat ook een module om de gegevens te bewaren in- en op te vragen uit de database.
Testprocedures in mijn library konden perfect een ExampleObject maken in de de database bewaren.
Mijn eindprogramma niet.
Als in in mijn eindprogramma directe sql code schreef, ging het daar wel.
De fout zat in het ExampleObject in de loadFromDb code.
If resDb.Available
$lId = resDb!id
- $lExternalId = resDb!Xternal_id
–> ipv resDb!External_id
In mijn applicatie deed ik eerst een controle op het bestaan van het order, waarbij die loadFromDb code gebruikt werd.
Verder had ik die load code nog nooit gebruikt (applicatie is nog in ontwikkeling), dus ik was die fout nooit tegengekomen.
Deze fout kan normaal niet voorkomen want ik maak altijd eerst de velden in de databank aan, en genereer daarna de persistence code met de dbInfoCode tool.
Dit veld was nadien toegevoegd, en deze lijn manueel toegevoegd. In het vervolg ga ik langs die tool en knip/plak de gegenereerde code …
Null Object of Connection is not opened
Soms krijg je deze fout bij een databaseverbinding die niet werkt (bv omdat server niet bereikbaar is of de database niet gestart is op je dev station).
Mijn database code zit in een module, bv MData
.
Ik gebruikte deze test:
Dim myResult As Result ' Try myResult = MData.getAllLines() ' If Error Then doLog(Error.Text) Else If myResult.Available Then ... use data... Endif
Maar dat is niet genoeg; als de fout, zoals hier, in de MData gebeurt, krijg je toch een situatie waar de Try geen fout geeft, maar myResult NULL is, en het programma crasht op myResult.Available: NULL Object.
Dim myResult As Result ' Try myResult = MData.getAllLines() ' If Error Or (myResult = NULL) Then doLog(Error.Text) Else If myResult.Available Then ... use data... Endif
Hier wordt de foutmelding: “Connection is not opened”
Wat ook werkt:
Dim myResult As Result ' Try myResult = MData.getAllLines() ' If (myResult = NULL) Then doLog(Error.Text) Else If myResult.Available Then ... use data... Endif
Hier wordt de foutmelding eveneens “Connection is not opened“.
Je slaat dan wel de test op If Error
over, kan dat…
Als je bv verkeerdelijk een paramater meegeeft in
MData.getAllLines(invalidparemater)
krijg je daar een foutmelding over: “Too many arguments“. Ja dus.
Bereik van variabelen als record id
Wanneer kies je in Gambas voor int, wanneer voor long?
Wanneer kies je in de databank voor een int(11), wanneer voor bigint(20)?
https://gambaswiki.org/wiki/lang/type
Kleinere:
Datatype Description Default value Size in memory
Boolean True or false. FALSE 1 byte
Byte 0...255 0 1 byte
Integer meer of minder:
Datatype Description Default value Size in memory
Short -32.768...+32.767 0 2 bytes
Integer -2.147.483.648...+2.147.483.647 0 4 bytes
Long -9.223.372.036.854.775.808...+9.223.372.036.854.775.807 0 8 bytes
Ik merk dat ik uit luiheid meestal “int” gebruik. Dikwijls is dat overkill, en is Short zeker genoeg. En als er geen negatieve getallen kunnen voorkomen (soms wordt een fout aangeduid door een negatief getal), en het maar over een klein getal gaat, dan is Byte zelfs genoeg.
Bij int
is het vooral opletten met de grenzen als het bv record nummers woden; 2 miljoen records is niet zo veel.
MariaDB datatypes
MySQL datatypes, bv de integer data types :
Vereiste opslag en bereik van integer data types in MySQL
Type | Opslag (Bytes) | Minimum waarde Signed | Minimum waarde Unsigned | Maximum waarde Signed | Maximum waarde Unsigned |
---|---|---|---|---|---|
TINYINT |
1 | -128 |
0 |
127 |
255 |
SMALLINT |
2 | -32768 |
0 |
32767 |
65535 |
MEDIUMINT |
3 | -8388608 |
0 |
8388607 |
16777215 |
INT |
4 | -2147483648 |
0 |
2147483647 |
4294967295 |
BIGINT |
8 | -263 |
0 |
263-1 |
264-1 |
Zie ook de tabel voor het doen overeenkomen van een type in de programmeertaal naar de databank, db-type mapping:
Datums, databanken en Gambas
Ik heb een paar keer problemen gehad met datum/tijd in Gambas, meestal gecombineerd met het opslaan in een databank, of er terug uit ophalen (*).
- Taalinstelling desktop: invloed op gambas programma *
- Datum uit een databank: welke vorm? *
- …
- Een datum achteruit; bv een week terug
- Een lege datum invullen in de databank: NOT NULL?
Bug
Op een bepaald moment werd er een bug gemeld op de mailinglist:
[Gambas Bug Tracker] Bug #1321: Converting date to string behavior change between 3.10 and 3.11
Gebruikers hadden ontdekt dat bepaalde programma’s, bepaalde broncode, niet meer werkte na een update van Gambas3 (overgang 3.10 naar 3.11 of hoger).
De bug-melding werd verworpen.
Correctie
Maar die verandering werd bevestigd; het was echter geen bug; ze was het gevolg van het verbeteren van een bug; er zat een fout in vroeger Gambas-code, en die was met deze versie-wissel gecorrigeerd, waardoor Gambas inderdaad anders reageert in sommige situaties.
Str() Val() Format() en Date() maken gebruik van de “locale”, de instellingen van de “desktop” (taal/land/tijd/etc).
CStr() gebruikt de UTC tijd.
Dus je moet kijken naar de instelling van de database en die van je desktop, bv GMT+0200
.
In één programma CDate() en Date() mengen zal waarschijnlijk problemen geven.
De interne manier om een datum of tijd bij te houden is een getal, relatief tov een denkbeeldig nulpunt.
Met Format(), Date() maak je een interpretatie waarin je tijdzone meegenomen wordt om het voor jou “aanschouwelijk juist” te maken.
Bv in Groot-Brittanië is een datum/tijd opgeslagen in een record.
Als jij die opvraagt en toont met Format() dan krijg je de tijd die het in jouw tijdszone was, niet wat letterlijk opgeslagen is in de database.
Je moet dus ook opletten (voor het verschil)
– of je de database een datum laat opslaan, bv automatisch (instelling db server) met de instelling timestamp.
– of je zelf een datum naar de database stuurt als tekst: .. values('2024-01-01 01:14:18')
– of je kan in je SQL statement de opdracht voor een datum geven
Database
De database (mysql/mariadb) heeft 5 tijdsgebonden opslagvormen (kolom):
- DATE = aleen de datum (1000-01-01-9999-12-31)
- DATETIME = datum + tijd (1000..:..- 9999...:..)
- TIMESTAMP datum + tijd (1970-20238!!!!)
- YEAR : alleen een jaartal (1901-2155)
- TIME : alleen een tijd (getal -838.. tot + 838.. ong 35 dagen)
Het 2038 probleem
Het hangt er natuurlijk een beetje vanaf wat je met die datums wil doen, en daarom moet je rekening houden met hun bereik, meestal vooral met hun hoogst mogelijke waarde, die voor sommige formaten gevaarlijk dichtbij komt.
Als je de datum enkel opslaat als leesbare informatie voor de programmeur, is 2038 van timestamp geen probleem, maar als het een veld is waar je verder conclusies uit gaat trekken gebaseerd op vergelijkingen met andere datum/tijd, berekeningen maken, sorteren enz, dan zie je de problemen al opduiken nog voor je op pensioen* bent. En timestamp is ook zuiniger met opslagruimte.
(* bv als je geboren bent na de default pc BIOS datum van 04-01-1980)
DATETIME is dus het veiligere alternatief, maar let op met de tijdszone.
Timestamp probeert de “huidige” tijdszone om te zetten naar UTC om de waarde op te slaan in de database, en terug te zetten naar de tijdszone (van de server**) bij het opvragen.
** dus niet de zone van de client als je bv vanop afstand gegevens opvraagt
Tijdzone
Vanaf Gambas 3.18 kan de tijdzone meegegeven worden:
(Old date string representation) space [ UTC | GMT ] [ + | - ] HH [ :MM ]
Om de algehele verwarring rond datums, (interne) opslag en weergave, tijdzone en formaten aan te pakken werd deze wiki pagina gemaakt, met oa:
Datums zijn geen strings
– Interne voorstelling
– Functies die werken met U.T.C. en American date format
– Functies die werken met local time
– Impliciete omvorming
– Datums zijn getallen
– Null datums en datums met alleen een tijdsdeel
– Datums bewaren
– Datums bewaren in een binair bestand
– Datums bewaren in een tekstbestand
– Datums en kalenders
Voor selectie van een datum, zie ook de wiki pagina over kalenders.
Bronnen
– mailinglist en bugtracker
https://lists.gambas-basic.org/pipermail/user/2018-May/064153.html
Datetimes versus timestamps in MySQL
https://gambaswiki.org/ wiki/doc/date, wiki/doc/calendar
Testen in Gambas met unittesting
Testen
Ik gebruikte al verschillende manieren om mijn programma’s te testen:
– ik dump allerlei waarden naar de output met print (die blijven ook werken in uitvoerbare programma’s)
– ik dump allerlei waarden naar de output met debug (die worden er uit gehaald bij compileren als je dat kiest)
– ik neem testcode op in mijn applicatie en stuur de uitvoer naar een optioneel zichtbaar te maken “log” (bestand of tekst op scherm).
– bij libraries schreef ik de testen in de main module, omdat die toch niet geëxporteerd wordt, dus niet zichtbaar wordt voor gebruikers. Wordt snel te veel.
– ik maak een aparte module “MTest” waar ik alle tests in steek. Ik moet die dan nog wel aanroepen uit bv de Main (library) of kan ze zelfs vanuit mijn draaiende applicatie aanroepen (bv via een testmenu in “hidden developer mode”).
– ik schreef een library MijnLib en maakte een testprogramma MijnLibTest en riep de testen aan vanuit Main, en zet ze aan of af door een commentaarteken voor de lijn te wissen/zetten. Wordt ook snel onoverzichtelijkt.
Maar dat is nog geen unittesten…
Formeel geÏntegreerd
Zoals altijd bij Gambas (althans mijn ervaring): als je iets nodig hebt, blijkt het ofwel al te bestaan, ofwel wordt het bijgemaakt, en kan je je eigen methodes vervangen door de geïntegreerde methodes in Gambas zelf.
Bij gebruik van de Gambas3 IDE viel me op dat er bij creatie van een nieuw bestand onder “bronnen”, behalve de opties “map”, “klasse”, en “module”, ook een optie “Test module” bestaat. Die maakt standaarde de testmodule “Test1” aan (die als bestandsnaam “Test1.test” heeft).
Waarschijnlijk is het overzichtelijker om een map te maken voor je tests (zoals ze in het voorbeeld doen); dus maak je eerst submap “Test”, en daarin de “Test1.test”. De testbestanden worden gebruikt in volgorde van hun bestandsnaam, en binnenin op volgorde van de methodenamen.
Een testmodule is in de linkse kolom herkenbaar aan een iets ander icoontje: een optionbox (aanvinkbaar hokje), en bij conventie laat je de naam voorafgaan door een T: TNaam (vgl module MNaam, form FNaam, class CNaam)
In de programmeeromgeving van Gambas3 druk je op F4 om de testen te starten.
Onderaan krijg je een vensterdeel met de resultaten van de tests. Bij het uitvoeren van de tests wordt een teller bijgehouden en onderaan krijg je een resultaat, bv als alles goed ging “PASSED”, anders “FAILED”.
Om de testen op te stellen heb je “Assert” te hulp:
Assert.Equals(uitdrukking1, uitdrukking2, commentaar)
Assert.Ok(uitdrukkingIsTrueOrNot, commentaar)
Assert.Error(commentaarBijErrorInTry_Something)
enz, Assert heeft een heleboel nuttige tests.
Gebruik
Als je helemaal nog geen code hebt, en gewooen een nieuwe test maakt “Test1”, en je probeert F4 krijg je:
1..0
# Ran ‘Test1’
#
# FAILED
En de voorbeeldcode (zie link onderaan) draait een succesvolle test en geeft:
1..5
Test THello.AHelloWorld
# I am the first test, because my name starts with A.
ok 1 – THello.AHelloWorld.7: HW strings should be equal
1..1
ok 1 – THello.AHelloWorld
(…enz 2, 3, 4 ..)
Test THello.Right
ok 1 – THello.Right.19: Hello.Right says Right
1..1
ok 5 – THello.Right# Ran ‘Testsuite: A: Run all tests’
#
# PASSED
Verfijnen
Als je wil kunnen kiezen welke tests je wel of niet draait, kan je “test suites” maken. In het test scherm (F4) krijg je rechts onderaan de knop om “Test suites” te maken, -draaien, -beheren, enz.
Plannen
Het is lonend om bij het programmeren voor bepaalde methodes/procedures/functies eerst de test te programmeren, en dan pas de methode zelf: je kan dan tijdens het programmeren van de methode onmiddellijk testen met je test.
Als je later aanpassingen aan je programma maakt, bedenk je eerst of de test moet veranderen, en daarna kan je de wijzigingen dan ook testen met je oorspronkelijke of aangepaste test.
Vooral bij libraries zijn testmodules interressant, ook voor algemene code in modules in je project.
Links
https://gambaswiki.org/wiki/doc/unittesting
https://nl.wikipedia.org/wiki/Unittesten
https://gitlab.com/gambas/gambas/-/blob/master/main/lib/test/gb.test/unittesthelloworld-1.0.0.tar.gz