5. Lær at Programmere

Mere om metoder 

 Mere om metoder


Indtil nu har vi set nogle forskellige metoder, puts og gets og så videre (Hurtig quiz: Lav en liste over alle de metoder du indtil nu har brugt. Der er 10 ialt. Svaret står nedenunder.) Men vi har ikke rigtig talt om hvad metoder er. Vi ved hvad de gør, men vi ved ikke hvad de er.

Men det er så også bare det de er: ting som gør noget.  Hvis objekter (som strenge, integers og floats) er navneordene i ruby sproget, så er metoderne udsagnsord. Og ligesom på dansk, kan du ikke have et udsagnsord uden at have et navneord til at udføre det. For eksempel 'at tikke' er ikke noget der bare sker. Et ur må gøre det. På dansk ville vi sige: Et ur tikker. På ruby'sk ville vi sige clock.tick (hvis vi regner med at 'clock' var et ruby objekt).Programmører ville sige at "vi kalder clockobjektets tick metode" eller at vi "kaldte tick på clock".

Nå, lavede du quizzen ? Fint. Jeg er sikker på at du kunne huske metoderne 'puts','gets' og 'chomp' fordi vi lige havde haft dem. Du havde sikkert også fundet adapter metoderne  .to_i og .to_s frem. Men fandt du så de sidste fire? Ja det er ingen andre end de gamle regnevenner +, -, * og / !


Som jeg tidligere sagde, behøver ethvert udsagnsord et navneord, så enhver metode skal have et objekt. Det er normalt let at se hvilket objekt der udfører metoden: det der det der kommer lige før punktummet, ligesom clock.tick eller i 101.to_s. Nogle
 gange er det ikke helt så tydeligt. For eksempel regnings metoderne. Men i virkeligheden er 5 + 5 bare en hurtig måde at skrive 5.+ 5 . For eks:

puts 'hej  '.+ 'verden'
puts (10.* 9).+ 9

hej verden 
99

Det ser ikke pænt ud at skrive på den måde så det ville vi aldrig gøre. Men det er vigtigt at forstå hvad der virkelig sker. (På min maskine giver dette også en advarsel, "warning: parenthesize argument(s) for future version". Det kørte fint koden men den fortæller mig at det ikke er let at se hvad jeg mener og beder om at bruge parenteser i fremtiden.) Dette giver os en dybere forståelse af hvorfor  vi kan skrive 'gris'*5 men ikke 5*'gris': 'gris'*5 beder 'gris' om at udføre miltiplikationen, men 5*'gris' beder 5 om at lave blive multiplicere sig selv 'gris' gange og lægge dem sammen...

Vi mangler selvfølgelig at forklare 'puts' og 'gets'. Hvor er deres objekter? På dansk kan du nogen gange udelade navneordet. For eksempel hvis  en skurk råber: "Dø!" mener han uden at sige det, den han råber til. Hvis jeg siger: puts 'at være eller ikke at være' , siger jeg i virkeligheden: self.puts 'at være eller ikke at være'. Så hvad er 'self'. Det er en speciel variabel som peget på det objekt du ligenu befinder dig i. Vi har endnu ikke forklaret hvordan man kan 'være i et objekt' men
indtil vi har gjort det kan vi sige at vi altid vil være i et stort objekt... nemlig hele programmet. Og heldigvis for os har programmet nogle få metoder såsom ' puts' og 'gets'.

jegkanikketroatjegharlavetdettenavnforatskrive3 = 3
puts jegkanikketroatjegharlavetdettenavnforatskrive3
self.puts jegkanikketroatjegharlavetdettenavnforatskrive3

3
3

Hvis du ikke helt kunne følge med her er det i orden. Det vigtige at forstå er, at alle metoder altid bliver gjort af et eller andet objekt, også selv om der ikke er et punktum foran det. Hvis du forstår det, så er det fjong. (kør ikke ovenstående, du vil få en fejl o.a.)


Smarte Streng metoder.


Lad os lære nogle sjove metoder til strenge. Du behøver ikke at huske dem alle. Du kan bare kigge på siden her igen, hvis du skulle glemme dem. Jeg vil bare gerne vise dig en lille del af hvad strenge kan gøre. Faktisk kan jeg ikke selv huske bare halvdelen af metoderne til strenge. Men det er ok, fordi der er masser af steder på internettet hvor der er lister over metoder og hvor de er forklaret. (Jeg viser dig  stederne  i slutningen af  bogen). Faktisk ønsker jeg slet ikke at kende til alle strengmetoder. Det er næsten ligesom at kende alle ordene i en ordbog. Jeg kan sagtens snakke dansk uden at kende alle ord i ordbogen... det er faktisk hele meningen med en ordbog !  At man ikke behøver at kende alle ordene ?

Så vores føtste striengmetode er 'reverse' som giver en baglæns version af en streng:

var1 = 'stop'
var2 = 'stresset'
var3 = 'kan du skrive dette bagfra?'

puts var1.reverse
puts var2.reverse
puts var3.reverse
puts var1
puts var2
puts var3

pots
tesserts
?arfgab etted evirks ud nak
stop
stresset
kan du skrive dette bagfra ?


Som du kan se laver 'reverse' ikke om på den oprindelige streng. Den laver bare en baglæns version af den. Det er grunden til at var1 stadig er 'stop' selv efter vi har kaldt var1.reverse.

En anden streng metode er 'length', som fortæller os antallet af karakterer (mellemrum medregnet) i strengen:
puts 'hvad er dit fulde navn?'
name = gets.chomp
puts 'Vidste du at der er  ' + name.length + ' bogstaver i dit navn:, ' + name + '?'


hvad er dit fulde navn?
gunner carstens
 

<TypeError: can't convert Fixnum into String>



Ups... noget gik galt her. og det ser ud til at det sker lidt efter linien navn=gets.chomp ... Ser du problemet ?

Problemet kommer med length: det giver os et tal, men vi ønsker en streng. Nå, det er let nok - vi laver bare en .to_s  og krydser fingre.

puts 'hvad er dit fulde navn?'
name = gets.chomp
puts 'Vidste du at der er  ' + name.length .to_s + ' bogstaver i dit navn:, ' + name + '?'


hvad er dit fulde navn?
gunner carstens
 

Vidste du at der er 15 bogstaver i dit navn gunner carstens ?
Nej det vidste jeg ikke. Bemærk at det er antallet af karakterer i mit navn, ikke antallet af bogstaver (tæl dem). Jeg vil tro at vi kunne skrive et program som beder om dit fornavn, mellem navn og efternavn og så lægger desse længder sammen ... forresten.. hvorfor gør du ikke det! Bare gør det. Jeg skal nok vente her.

Lavede du programmet ? Godt. Det er sjovt at programmere, er det ikke. Når du har læst nogle få kapitler mere, vil du blive forbløffet over hvad du kan lave.

Der er også nogle strengmetoder som kan ændre strengens store og små bogstaver. 'upcase' ændrer alle små bogstaver til store bogstaver og 'downcase' ændre alle store bogstaver til små bogstaver. 'swapcase' bytter om på små og store bogstaver og endelig 'capitalize' er ligesom 'downcase' bortset fra at den laver det første bogstav stort hvis det er et bogstav.


letters = 'aAbBcCdDeE'
puts letters.upcase
puts letters.downcase
puts letters.swapcase
puts letters.capitalize
puts ' a'.capitalize
puts letters


AABBCCDDEE
aabbccddee
AaBbCcDdEe
Aabbccddee
 a
aAbBcCdDeE

Ret almindelige ting. Som du kan se fra linien: puts ' a'.capitalize. så laver den kun den første karakter, ikke det første bogstav, stort. Også, som vi før har set i alle metodekaldene, så er bogstaverne uændrede. Jeg ønsker ikke at tvære i det men det er vigtigt at forstå. Der findes metoder som ændrer objektet men vi har ikke set nogen endnu og vi vil vente lidt med det endnu.

Den sidste af de smarte strengmetoder vi vil se på er til at få det til at se smart ud - eller visuel formattering som man kalder det. Den første, 'center' lægger  mellemrum  til betyndelsen og slutningen af strengen for at få det til at stå i midten.  Ligesom du er nødt til at fortælle 'puts' hvad det er du vil skrive og '+' hvad det er du vil lægge til, må du også fortælle 'center' hvor bred den centrerede streng skal være. Så hvis jeg ønskede at centrere linierne i et digt kunne jeg gøre sådan her:

lineWidth = 50
puts(                'Old Mother Hubbard'.center(lineWidth))
puts(               'Sat in her cupboard'.center(lineWidth))
puts(         'Eating her curds an whey,'.center(lineWidth))
puts(          'When along came a spider'.center(lineWidth))
puts(         'Which sat down beside her'.center(lineWidth))
puts('And scared her poor shoe dog away.'.center(lineWidth))


                Old Mother Hubbard
               Sat in her cupboard
            Eating her curds an whey,
             When along came a spider
            Which sat down beside her
        And scared her poor shoe dog away.


Hmmm .. jeg er ikke sikker på at det er sådan digtet  er, men jeg er for doven til at slå det op. (Jeg ville også sætte alle .center lineWidth op over hinanden så jeg satte alle disse mellemrum ind foran strengene. Det gjorde jeg bare for skønhedens skyld. Programmører har ofte stærke følelser med hensyn til hvad de mener er smukt og de er ofte uenige om det. Jo mere du programmerer jo mere vil du lave din egen stil.) Nu vi taler om at være doven, så er det faktisk ikke altid dårligt når man programmerer. Se for eksempel hvordan jeg gemte bredden i digtet i en variabel 'lineWidth'. Det lavede jeg for senere at kunne lave det bredere. Jeg skal kun lave den ene linie om i toppen af programmet, i stedet for hver linie som indeholder centrering. Med et meget langt digt kunne dette tage rigtig lang tid. Den slags dovenskab er en dyd indenfor programmering.


Lige med hensyn til centrering... du lagde måske mærke til at det ikke er så smukt som hvis det blev lavet af et tekstbehandlingsprogram. Hvis du virkelig vil have perfekt centrering, og måske en pænere font, så skulle du bare bruge et tekstbehandlingsprogram. Ruby er et vidunderligt redskab, men der findes ikke noget redskab der er det rigtige redskab til alle jobs.

De andre to strengformatterings metoder er 'ljust' og 'rjust', som står for venstre indrygning og højre indrygning. De ligner 'center' bortset fra at de indtykker strengen med mellemrum i henholdsvis venstre og højre side. Lad os se hvordan alle 3 virker:


lineWidth = 40
str = '--> text <--'
puts str.ljust  lineWidth
puts str.center lineWidth
puts str.rjust  lineWidth
puts str.ljust (lineWidth/2) + str.rjust (lineWidth/2)


--> text <--
              --> text <--
                            --> text <--
--> text <--                --> text <--


Nogle ting du skulle prøve


 * Skriv et program du kalder 'den vrede lærer'. Den skal groft spørge hvad det er du vil, ligemeget hvad du skriver skal den vrede lærer råbe det samme tilbage til dig, og så smide dig ud af klassen. For eks hvis du skrev: jeg vil gerne ville have fri, så skal programmet råbe tilbage: SIG MIG ENGANG: HVAD MENER DU MED "JEG VIL GERNE HAVE FRI"?  KAN DU SE AT KOMME UD I EN FART!

* Her er noget du kan prøve for at lege mere med 'center'. 'ljust' og 'rjust': Skriv et program som viser en indholds fortegnelse der ser således ud:

                Indholdsfortegnelse

Kapitel  1:  Tal                        side 1
Kapitel  2:  Bogstaver         side 72
Kapitel  3:  Metoder            side 118

 Sværere matematik
(Dette afsnit er helt valgfrit. Man skal kunne en hel del matematik for at lave dem. Hvis du ikke er interesseret kan du gå lige til næste kapitel, selvom det godt kan være du engang vil kunne få brug for afsnittet om Tilfældige tal).

Der er ikke nær så mange tal metoder som der er strengmetoder (selv om jeg stadig ikke kender dem alle sammen) Her vil vi kigge på resten af regnemetoderne. en tilfældig tal metode og selve Math objektet med dens trigonometriske og trancendentale metoder.

 Mere regning


De andre to regne metoder er ** (eksponential) og % (modulus). Så hvis du vil sige 'fem-i-anden' i ruby, så ville du skrive 5**2. Du kan også bruge floats som eksponent så hvis du vil have kvadratroden af 5 kunne du skrive 5**0,5. Modulus metoden giver dig det overskydende efter en division med et tal. For eksempel. hvis du deler 7 med 3 så får du 2 med 1 i overskud. Modulus er derfor 1. Lad os se det i et program:

puts 5**2
puts 5**0.5
puts 7/3
puts 7%3
puts 365%7


25
2.23606797749979
2
1
1


I den sidste linie kan vi se at i et år der ikke er skudår findes der et antal uger plus 1 dag. Hvis din fødselsdag er på en tirsdag i år, vil det være på en onsdag næste år. Du kan også bruge float med modulus metoden. Det virker faktisk på den eneste fornuftige måde det kan... men jeg vil lade dig selv lege med den.

Der er en sidste metode som vi vil nævne inden vi går til tilfældig-tal-generatoren: abs hedder den. Den giver den absolutte værdi af et tal:


puts  ((5-2).abs)
puts  ((2-5).abs)


3
3


Tilfældige tal


Ruby kommer med en ret god generator af tilfældige tal. Metoden som giver et tilfældigt valgt tal er 'rand'. Hvis du bare kalder 'rand' vil du få en float større end eller lig med 0,0 og mindre end 1,0. Hvis du giver en integer til rand (for eksempel 5) vil den give dig en integer større end eller lig med 0 og mindre end 5 (altså 5 tilfældige tal, fra 0 - 4)

Lad os se 'rand' i virkeligheden. (Hvis du genindlæser denne side, vil tallene skifte hver gang. Du vidste godt at jeg faktisk kørte alle disse programmer, gjorde du ikke ?) (i den engelske udgave, forstås)
puts rand
puts rand
puts rand
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(1))
puts(rand(1))
puts(rand(1))
puts(rand(99999999999999999999999999999999999999999999999999999999999))
puts('DMI siger at der er  '+rand(101).to_s+'% risiko for regn,')
puts('men man skal ikke have for meget tillid til DMI.')


0.652222548951857
0.771095429829019
0.0694234975924535
75
55
80
0
0
0
90692780843151765280549351123889336491755303293884220200861
DMI siter at der er 26% risiko for regn,
men man skal ikke have for meget tillid til DMI.


 Bemærk at jeg brugte rand(101) for at få tal fra 0 til 100 tilbage. og rand(1) giver altid 0. Den mest almindelige  fejl jeg ser med 'rand' er at man ikke har forstået rækken af mulige værdier. Den kan selv professionelle programmører lave og selv i programmer som du kan købe i forretninger. Jeg har fakrisk en CD afspiller som hvis den bliver at til 'tilfældig afspildning' afspiller alle sange undtagen den sidste. ( Jeg tænker også på hvad der ville ske hvis jeg havde sat en CD i med et eneste nummer)

 Nogle gange ønsker du måske at returnere de samme tilfældige tal i den samme rækkefølge på to forskellige kørsler af programmet (for eksempel lavede jeg engang et program der tilfældigt skabte en tilfældig skabt verden i et computerspil. Hvis jeg fandt en verden som var rigtig sjov. kunne jeg godt tænke mig at spille det igen eller sende det til en ven. For at gøre det må du sætte 'seed'  som du kan gøre med 'srand' . Som her:

srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts ''
srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))

24
35
36
58
70

24
35
36
58
70



Du vil få det samme hver gang du giver den det samme tal. Hvis du gerne vil have forskællige tal igen (som hvis du ikke bruger srand) så skal du bare kalde srand 0.  Det giver den et virkelig skørt tal. hvor den blandt andet bruger  din computers nuværende tid ned til millisekunder.


 The Math Objekt


Lad os til sidst se på Math objektet. Vi kan lige så godt bare gå i gang:

puts(Math::PI)
puts(Math::E)
puts(Math.cos(Math::PI/3))
puts(Math.tan(Math::PI/4))
puts(Math.log(Math::E**2))
puts((1 + Math.sqrt(5))/2)


3.14159265358979
2.71828182845905
0.5
1.0
2.0
1.61803398874989


Det første du formodentlig lagde mærke til var måske tegnet :: Den kaldes scope operatoren og er fakrisk ud over hvad vi skal lære i denne bog. Lad os nøjes med at sige at du kan bruge Math::PI præcist som du regnede med.

Som du kan se kan Math  alle de ting som du ville forvente af en god videnskabelig regnemaskine. Og som altid, er floats meget tæt på at give de rigtige svar.

Nå lad os strømme afsted.