Kidsbook

Laget av Tallak Tveide / @tallakt

Du kan hente opp denne presentasjonen på din egen maskin på adressen

http://ruby.galak.se

Dette er presentasjonene til et kursopplegg for ungdomsskole elever som går over fem kvelder med tre timer per gang.

Besøk gjerne Facebook siden vår for spørsmål på https://www.facebook.com/groups/625690284169137/

Forberedelser

Før første kursdag er det noen ting som du gjerne kan forsøke å løse på egenhånd for å spare tid.

Du kan ta med din egen bærbare datamaskin. Om den kjører Windows, Mac OS X eller Linux betyr lite.

Om du vil så vil det være maskiner på kurset du kan låne.

Installere Ruby

Har du Mac OS X eller Linux er det sannsynlig at Ruby allerede er installert på maskinen din. Du kan sjekke dette med kommandoen:

$ ruby --version
ruby 2.2.0p0 (2014-12-25 revision 49005) [i686-linux]

Hint: Du skal ikke skrive $ tegnet, denne angir hvor du skal skrive dine kommandoer.

Om du ikke har Ruby finner du det på http://ruby-lang.org. Du kan bruke en versjon som er 1.8.7 eller nyere.

På Windows anbefaler vi å velge 'Add Ruby to Path' under installajonen.

Om du har problemer med å installere Ruby får du hjelp på kurset.

For å skrive programfiler bruker vi en tekst editor. Noen gratis anbefalinger:

Vim og Emacs er to veldig avanserte editorer som brukes mye av profesjonelle. Hvis du allerede bruker en av disse er det ok.

Ta helst med en USB minnebrikke på kurset slik at du kan ta en kopi av filene dine når du reiser hjem for dagen.

Hvis du har (eller registrerer) en gratis konto på GitHub er det mulig å legge koden din der. Vi hjelper i såfall til om nødvendig.

Et annet alternativ er å bruke Dropbox href="http://www.dropbox.com/" | Dropbox

Vel møtt!

Dag 1 - Ruby

I dag går vi gjennom grunnleggende Ruby og lager noen enkle (og mindre enkle) script.

Hva er Ruby?

Ruby er et 20 år gammelt programmeringsspråk som ble laget av japaneren Matz (Yukihiro Matsumoto).

Matz

Han ville lage et språk som gjorde programmering gøy

Ruby er likevel et språk som kan brukes til mye. Twitter er det mest kjente nettstedet som har brukt Ruby. De brukte det til å lage hele hjemmesiden sin

Ruby script

Ruby tar en tekstfil og utfører kommandoer linje for linje.

Hvis vi har en tekstfil med

# i filen hello.rb
puts "Hello World!"

Når vi kjører den får vi

$ ruby hello.rb
Hello World!

Hello Ruby

Tradisjonen i programmering er at det første programmet man lærer i ett nytt språk skal skrive ut teksten "Hello World"

Vi skal lage et slikt program

Windows

Lag en mappe som heter c:\min_ruby

Mac OS X og Linux

Lag en mappe min_ruby i hjemmekatalogen din.

Åpne tekst editoren og skriv:

puts "Hello World!"

Lagre filen i katalogen din med navnet hello.rb

Ruby script kjører vi vanligvis i et terminalvindu.

Windows

Trykk på start knappen, så `Run...` og skriver `cmd`. For å endre katalog og kjøre scriptet ditt skriver du

c:\Program Files> cd c:\min_ruby
c:\min_ruby> ruby hello.rb

Mac OS X og Linux

Kjør `Terminal` og skriv:

$ cd ~/min_ruby
$ ruby hello.rb

Variabler

Variable brukes til å lagre verdier

a = 1
b = a + 2
puts b     # Skriver ut 3
b = 10     # her setter vi b på nytt
puts b     # Skriver ut 10

Variable må begynne med liten bokstav, og ikke inneholde spesielle tegn. Noen lovlige variabelnavn er:

a

tallet

svar5

et_viktig_tall

Det lønner seg å unngå norske bokstaver i variabelnavn

Variable med STORE BOKSTAVER er konstanter i Ruby. Konstanter får man ikke endre etter at de først er satt

MENINGEN_MED_LIVET_OG_ALT = 42

Konstanter kan ofte gjøre koden lettere å lese

Verdier

Verdier kan ha forskjellige typer, de vanligste er:

Fixnum Hele tall som 1 eller -100
Float Desimaltall som 1.5 og 100.0
String Tekster, f.eks. "Ruby er topp!"
Symbol brukes som nøkler :ruby
true og false angir sannhet
nil mangel på verdi

Strenger

puts "Ruby"      # Skriver Ruby
puts 'Ruby'      # Skriver også ut Ruby
a = "Yukihiro"
b = "Matsumoto"
puts "#{a} #{b}" # Skriver Yukihiro Matsumoto
a = "Yukihiro"
b = "Matsumoto"
puts "#{a} #{b}"

På den siste linjen vises en fin måte å sette verdier sammen til en streng. Du kunne også gjort

a = "Yukihiro"
b = "Matsumoto"
puts a + " " + b # Skriver også Yukihiro Matsumoto

Symboler

Symboler brukes mye i Ruby fordi de er så greie

Man kan tenkte at symboler er som strenger

valg = :ruby
puts "Hei Java" if valg == :java
puts "Hei Ruby" if valg == :ruby

Koden over vil skrive ut `Hei Ruby`

Konvertere verdier

Bruker vi `+` må vi passe på at begge verdiene vi skal sette sammen passer i hop

1 + "10"    # TypeError: String cant be coerced into Fixnum

Man kan gjøre en streng om til et heltall med `to_i`.

1 + "10".to_i
 => 11

Eller motsatt, et heltall til en streng med `to_s`

1.to_s + "10"       # to_s gjør til streng
 => "110"

`to_f` konverterer en streng til et desimaltall:

1 + "10.5".to_f
 => 11.5

Computeren vil snakke med deg!

`puts` og `gets` er en enkel måte å skrive til skjermen og spørre brukeren om ting

puts "Skriv noe"
svar = gets
puts "Du skrev #{svar}"

`puts` er mye brukt av profesjonelle kodere

IRB

IRB er et nyttig verktøy som følger med Ruby. Her kan du prøve ut Ruby kode og få resultatet umiddelbart. Du trenger ikke opprette en tekstfil.

IRB er fin for eksperimentering!

$ irb
irb(main):001:0> r = "Ruby"
 => "Ruby"
irb(main):002:0> r.upcase
 => "RUBY"

Noen oppgaver

  • Lag et script som spør om navnet og hilser tilbake (Hva heter du? Matz. Hei Matz!)
  • Lag et skript som spør om tre tall og regner ut gjennomsnittet

Metoder

Alle verdiene i Ruby har metoder. For eksempel har verdien "Ruby" en metode `length` som angir hvor mange tegn den har.

tekst = "Ruby"
tekst.length
 => 4
"Ruby".length
 => 4

Forskjellig type verdier har forskjellige metoder

-100.abs
 => 100
"     Matz     ".strip
 => "Matz"
-100.strip
NoMethodError: undefined method `strip' for -100:Fixnum

Noen metoder vil trenge ekstra informasjon som parametre

tall = 16
tall.div(5)    # Divisjon med hele tall
 => 3

I Ruby er det ikke nødvendig å ha parenteser rundt parametrene, dette er også ok:

tall.div 5
 => 3

Flere parametre listes opp adskilt av komma

tekst = "Ruby"
tekst.center(30, "_")
 => "_____________Ruby_____________"

Betingelser

Vi bruker `if` til å velge om en kodeblokk skal utføres

verdi = 1
if verdi > 10
  puts "En er større enn ti? Her er noe galt"
end

Vi kan også legge til en `else` blokk der det trengs

verdi = 1
if verdi > 10
  puts "En er større enn ti? Her er noe galt"
else
  puts "En er ikke større en ti, som forventet"
end
@tenderlove

Gjentakelse

For å gjenta en oppgave kan vi bruke løkker

10.times do |n|
  puts "Dette er linje #{n}"
end

For å gjenta en kodeblokk til noe blir sant bruker man `while`

inntastet = 0
while inntastet != 5 do
  puts "Skriv et tall, 5 for å avslutte"
  inntastet = gets.to_i
end

Oppgave: De ti navnene

Lag et program som skriver ut ti linjer. De første fem er fornavnet ditt, de siste fem er etternavnet.

Oppgave: Gjett det hemmelige tallet

Skriv et program som lager et tilfeldig tall mellom 0 og 9. Spør brukeren hvilket tall det er, helt til tallet er gjettet. Avslutt med en gratulasjon.

Tips: For å lage tilfeldige tall kan man bruke

tilfeldig_tall = rand(0..9)

Dag 2 - Mer Ruby

I dag skal vi kikke på mer avanserte datastrukturer i Ruby og lese og skrive til filer.

Lister

liste = [1, 2, 3, 4]
liste.push(5)         # legg til på slutten
 => [1, 2, 3, 4, 5]
liste.pop             # hent siste element
 => 5
liste
 => [1, 2, 3, 4]
liste.shift           # hent første element
 => 1
liste
 => [2, 3, 4]
lang_liste = liste + [:a, :b, :c]
 => [2, 3, 4, :a, :b, :c]
en_tom_liste = []

Verdiene i en liste har en indeks som begynner på null. Indeksen kan brukes til å lese en eller fler verdier.

liste = [1, 2, 3, 4]
den_forste = liste[0]
 => 1
de_tre_forste = liste[0..2]
 => [1, 2, 3]

Each

En grei måte å gjøre noe med alle verdiene i en liste er å bruke `each` metoden.

noen_tall = [4, 6, 8, 10]
sum = 0

noen_tall.each do |tall|
  sum = sum + tall
end

# Når vi kommer hit er sum lik 28

Oppgave: Vi sorterer tall

På neste side er det en kodesnutt som sorterer tall brukeren skriver inn. Kopier eller skriv av koden inn i en ruby fil som du kjører. Se om du kan finne ut hva hver linje gjør

# nulltiling av variable
inntastet = nil
liste = []

# vi spør brukeren om tall, og legger de til listen vår
while inntastet != -1
  puts "Skriv et positivt heltall og avslutt med -1"
  inntastet = gets.to_i
  if inntastet >= 0
    liste.push(inntastet)
  end
end# vi lager en sortert liste ved å ta ut den minste verdien
sortert = []
while liste.any?
  minste = liste.min
  liste.delete(minste)
  sortert.push(minste)
end

# skriv ut resultatet
sortert.each do |tall|
  puts tall
end

Ruby har sortering innebygd

[2, 5, 6, 3, 6].sort
 => [2, 3, 5, 6, 6] 

Hash

I Ruby er en hash en tabell hvor man slår opp en verdi utfra en nøkkel

Eksempler hvor man ville brukt en hash er:

  • en telefonkatalog
  • en bok med tittel, forfatter og antall sider


En hash kan minne veldig om en vegg med bankbokser. En nøkkel gir adgang til innholdet i den ene boksen.

Eksempel 1: Telefonkatalogen. Nøkkelen i hashen vår er navnet, verdien er telefonnummeret

katalog = {}     # start med en tom hash
katalog["Matz"] = "555-555-5555"
katalog["Tenderlove"] = "888-888-8888"

Når vi senere skal slå opp et nummer gjør vi:

katalog["Matz"]
 => "555-555-5555"
katalog["Yukihiro Matsumoto"]  # finnes ikke
 => nil

I en hash er har hver nøkkel bare en verdi

katalog = {} 
katalog["Matz"] = "555-555-5555"
katalog["Matz"] = "666-666-6666" # denne overskriver 555-555-5555
katalog["Matz"]
 => "666-666-6666"

Eksempel 2: Lagre bok informasjon

bok = {}     # start med en tom hash
bok[:tittel] = "Ready Player One"
bok[:forfatter] = "Ernest Cline"
bok[:sider] = 384

Og så kan vi bruke bok variabelen slik

t = bok[:tittel]
f = bok[:forfatter]
s = bok[:sider]
beskrivelse =  "#{t} av #{f}, #{s} sider"
 => "Ready Player One av Ernest Cline, 384 sider"

Legg merke til at telefonkatalogen har mange nøkler, mens boken vår har noen få faste nøkler

Oppgave

Lag en liste med fem navn. Gi alle personene et terningkast 1 til 6. Skriv ut hvem som fikk det høyeste tallet. Vi skal lagre resultatene i en hash med navn som nøkkel og terningkast som verdi.

Siden hash blir mye brukt i Ruby, finnes noen enklere måter å skrive de inn på

bok = {
  :tittel => "Ready Player One",
  :forfatter => "Ernest Cline",
  :sideantall => 384
}
bok = {
  tittel: "Ready Player One",
  forfatter: "Ernest Cline",
  sideantall: 384
}

Det er fullt mulig å kombinere en liste og hasher

liste = []
liste.push({twitter: "matz", land: "Japan"})
liste.push({twitter: "tenderlove", land: "USA"})
liste
 => [
      {:twitter=>"matz", :land=>"Japan"}, 
      {:twitter=>"tenderlove", :land=>"USA"}
    ] 
liste[1][:land]
 => "USA"

Lister med hasher er ganske kompleks programmering. Det er ok hvis du ikke skjønner det med en gang.

Filer

# Åpne en fil for skriving
File.open("min_fil.txt", "w") do |fil|
  fil.puts "A"
  fil.puts "B"
end

# Åpne samme fil for å lese tilbake
File.open("min_fil.txt") do |fil|
  while not fil.eof?               # `eof?` angir end-of-file
    puts fil.gets
  end
end

Slik ser det omtrent ut hvis vi kjører scriptet

$ ruby lese_og_skrive_til_fil.rb
A
B

Filer er den måten en datamaskin kan lagre data mellom hver gang den startes på nytt. Filen legger seg på datamaskinens harddisk. Slike filer kan man åpne og lese i teksteditoren din.

Oppgave: lagre data man skriver inn

a) Lag et script som henter inn tre tall med `gets` og skriver dem ut til en fil

b) Lag et script for å lese tallene i filen og skriv ut summen

c) Hent filen opp i en tekst editor

En tekstfil inneholder alle bokstaver adskilt av linjeskift tegnet. Dette tegnet vises som strengen "\n"

Når vi leser linjer i en fil får vi tilbake disse tegnene også. Det er vår jobb å fjerne dem fra strengene

innhold = File.read("min_fil.txt") # leser alt i et jafs
linjer = innhold.each_line         # splitter opp linjene
forste_linje = linjer.first
 => "A\n"
forste_linje.strip
 => "A"

Noen ganger må vi ha en plan B om filen ikke finnes

filnavn = "min_fil.txt"
verdi = nil
if File.exist?(filnavn)
  verdi = File.read(filnavn)
else
  verdi = "HELT TOMT"
end

På de neste sidene finner du noen oppgaver. Her kan du velge noe som passer

Oppgave: Stein Saks Papir

Les et tall fra brukeren. Stein saks papir er som for listen under. Datamaskinen velger så et tilfeldig valg. Angi hvem som vant, eller spill en ny runde hvis det ble uavgjort.

1 Stein
2 Saks
3 Papir

Tips:

tilfeldig_tall = rand(1..3)

if tilfeldig_tall == 1 then
  # kode her
end

Oppgave: Yatzy - Har vi fått hus?

Når du starter programmet kaster vi fem terninger. Sjekk om man har fått hus. Tips: legg terningkastene i en liste og bruk `liste.sort`. Vi skal da enten ha 3+2 like eller 2+3 like.

Oppgave: To terninger sammen

La datamaskinen kaste to terninger hundre ganger. Pluss sammen antall øyne for hvert kast. Lagre summen i en hash med sum som nøkkel og antall kast som verdi. Skriv ut resultatene. Tips:

tellere = {}

# Initialiser hash med null
(2..12).each do |sum|
  tellere[sum] = 0
end

# kast to terninger og øk teller
sum = rand(1..6) + rand(1..6)
tellere[sum] = tellere[sum] + 1

Oppgave: Sinus

Lag en evig løkke som skriver ut "Matz" som en sinus. Tips: bruk elementer fra koden nedenfor.

s = Math.sin(0.3)   # Sinus til et tall

desimaltall = 55.5
heltall = desimaltall.to_i # runder av til et heltall

innrykk = 10 * " "
puts "#{innrykk}Matz"

# evig løkke
loop do
  # kode her
end

Oppgave: Caesar Cipher (vanskelig)

Dette er en gammel form for kryptering hvor alle bokstavene blir forskjøvet. Man angir nøkkelen, og hver bokstav forskyves så mange bokstaver videre. Hvis nøkkelen er 2 vil "A" byttes ut med "C", "B" blir til "D", "Y" blir til "A" etc. For å gjøre det enklere støttes bare A-Z, tilsammen 26 bokstaver. Dekryptering gjøres ved å kjøre ny kryptering med nøkkel 26 - (forrige nøkkel). (Hjelpekode på neste side) Programflyt:

  • Spør om nøkkelen (tall fra 1 til 25)
  • Spør om teksten som skal krypteres
  • Skriv ut den krypterte teksten
"MATZ".chars
 => ["M", "A", "T", "Z"] 
["M", "A", "T", "Z"].join
 => "MATZ"
"A".next
 => "B"

Oppgave: Anagrammer

denne linken fra Norsk Scrabble Forbund finnes en tekstfil med norske ord. Filen ser omtrent lik ut:

ACTINIUMENE subst
ACTINIUMET subst
ACTION subs

Lag et program som spør om et ord og så finner anagrammer for det (ord med samme bokstaver i en annen rekkefølge). Tips på neste side.

"ACTINIUMENE subst".split
 => ["ACTINIUMENE", "subst"] # BEINET og BITENE er anagrammer
"BEINET".chars.sort.join
 => "BEEINT"
"BITENE".chars.sort.join
 => "BEEINT"# pass på at det brukeren skriver blir likt med bokstavene i ordlisten
# Fjern blanke tegn og gjør til store bokstaver
inntastet = gets.strip.upcase

Oppgave: Kriminalitet (vanskelig)

På hjemmesiden til The District of Columbia finnes en oversikt over alle lovbrudd som er begått i 2013. Lag en oversikt over hvor mange lovbrudd som er gjort av hver type (fjerde verdi) og skriv det ut som en tabell. Bonusoppgave: Finn ut hvilken type kriminalitet som skjedde hyppigst for hver klokketime

"A,B,C,D,E".split(",")
 => ["A", "B", "C", "D", "E"] dato_tid = DateTime.parse("1/2/2013 3:00:00 PM")
dato_tid.hour
 => 15

Oppgave: Mastermind (supervanskelig)

Implementer spillet mastermind. Datamaskinen sitter med den hemmelige løsningen. Tips: Når brukeren skal gi svar kan han ha en bokstav per farge, og skrive fire bokstaver. Programmet svarer så med hvor mange som var riktig farge på riktig sted, og hvor mange som var riktig farge på feil sted.

G R U L H S
Grønn Rød Gul Lilla Hvit Sort
# lage datamaskinens hemmelige løsning
FARGER = ["G", "R", "U", "L", "H", "S"]
losning = []
4.times do
  indeks = random(0..5)
  losning.push(FARGER[indeks])
end

http://en.wikipedia.org/wiki/Mastermind_(board_game)

Dag 3 - HTML og Web

Vi kikker litt på HTML og på hvordan en hjemmeside fungerer

Kidsbook...

I løpet av de siste tre dagene skal vi bygge en hjemmeside med Ruby. Når vi er ferdige har vi bygd en veldig enkel Facebook lignende side hvor man kan legge inn innlegg.

HTML

HTML er det språket som man beskriver en web side med.

HTML er ikke et programmeringsspråk, men en måte å beskrive en web side på

<!DOCTYPE html>
<html>
  <head>
    <title>Hallo!</title>
    <meta charset="UTF-8"> 
  </head>
  <body>
    <p>Hallo verden!</p>
  </body>
</html>

Prøv å skrive inn dette i en tekstfil som du kaller `hello.html`. Åpne filen i nettleseren din (Firefox, Safari, Chrome, Internet Explorer).

I HTML har vi `tagger` som åpner og som lukker. De opptrer parvis slik som dette:

<div> </div>

Hva slags tag vi lager bestemmer hva som blir skrevet i browseren. `div` taggen gjør ingenting annet enn å gruppere andre tagger og tekst.

HTML bryr seg ikke om mellomrom og linjeskift. Dette

P taggen inneholder vanligvis et avsnitt med tekst

er likt med dette:

P taggen inneholder vanligvis et avsnitt med tekst

En HTML fil deles opp opp i `head` og `body`. Body inneholder alt som blir vist på siden. Head inneholder tittelen som vises øverst i nettleseren, og spesielle tagger.

Tabellen på neste side viser noen vanlige tagger

heading 1 <h1> brukes til overskrifter
heading 2 <h2> brukes til overskrifter
heading 3 <h3> brukes til overskrifter
paragraph <p> inneholder et avsnitt med tekst
division <div> gruppering
anchor <a href="..."> en lenke til noe annet
image <img src="..."> bilder

Bilder

Du kan sette inn et bilde fra en komplett adresse (URL) slik

<img src="http://goo.gl/TZjd4Q"></img>

eller du kan hente bildet fra samme sted

<img src="kidsbook_logo.png"></img>

HTML filen og bildet må ligge i samme katalog

Hyperlenker

Lenker til komplette adresser lages slik

<a href="http://www.duckduckgo.com">trykk her for å søke</a>

eller du kan hoppe til en annen side fra fra samme sted

<a href="andre.html">her er den andre siden min</a>

Oppgave: Lag et utkast til din Kidsbook

Lag en side som skal bli Kidsbook. Siden skal ha:

  • tittelen skal være `Kidsbook`
  • en overskrift, `Siste innlegg`
  • fire innlegg med en tekst du bestemmer
  • hvert innlegg skal ha navnet på avsender
  • Kidsbook logoen lagret i samme katalog som HTML filen
  • øverst på siden en lenke til `login` siden som vi lager senere


Vent lengst mulig med å kikke på løsningsforslaget

CSS

Web siden vi laget ser litt kjedelig ut. Mens teksten på en web side er bestemt av HTML kodene, er utseendet bestemt av CSS filen

body {
  background-color: powderblue;
}

.innlegg-tekst {
  margin-top: 50px;
}

.avsender {
  color: steelblue;
}

Vi kommer ikke til å gå så mye inn på CSS her, så vi skriver av denne teksten og lagrer som `kidsbook.css`

Neste steg er å koble HTML filen sammen med CSS filen. Det ser omtrent sånn ut

<head>
  <title>Kidsbook</title>
  <link rel="stylesheet" type="text/css" href="kidsbook.css">
</head>

For at valgene i CSS filen skal tre i kraft må de matche med tagger i HTML filen. Stilen

.avsender {
  color: steelblue;
}

vil matche med denne HTML taggen:

<p class="avsender">Hilsen Doffen</p>

Resultatet vil være at avsnittet blir mørkeblå, som fargekoden steelblue angir. Farger er beskrevet her

Oppgave: vi legger til litt stil

For siden vi laget først skal vi bruke CSS filen. Gjør slik av både innlegg og avsendere er påvirket av CSS stilene. Løsningsforslag.

Påloggingsskjema

Vi skal lage en HTML fil nummer to hvor man får mulighet til å logge seg inn.

Vi gjør det veldig enkelt med en boks hvor man skiver inn navnet sitt, og en knapp for å bekrefte

Her er noen tagger vi kan bruke

<form> omslutter alle elementer i ett skjema
<textarea> en stor boks for tekst
<input type="text"> en liten boks for tekst
<input type="submit"> knappen for å sende inn skjemaet

Et enkelt skjema for innlogging ser da omtrent sånn ut

<form method="POST" action="/behandle-login">
  <p>
    <input type="text" name="avsender"></input>
  </p>

  <p>
   <input type="submit" value="Logg inn" />
  </p>
</form>
<form method="POST" action="/behandle-login">
  <p>
    <input type="text" name="avsender"></input>
  </p>

  <p>
   <input type="submit" value="Logg inn" />
  </p>
</form>

I dette skjemaet oppgir vi at aksjonen når vi trykker på knappen skal være `behandle-login`. Tenk at det er som

<a href="/behandle-login">

men som gjelder for skjemaer

<form method="POST" action="/behandle-login">
  <p>
    <input type="text" name="avsender"></input>
  </p>

  <p>
   <input type="submit" value="Logg inn" />
  </p>
</form>

Navnet `avsender` trenger vi når vi senere mottar dataene fra skjemaet

Oppgave: innloggingssiden

Lag en html fil for pålogging. Sjekk at lenken fra hovedsiden fungerer. Løsningsforslag her.

Web serveren

Filene som ligger på din datamaskin vil ikke være tilgjengelige for andre maskiner. Vi trenger en web server for å gjøre dette

Vi skal bruke Sinatra som web server. Sinatra er et system som brukes av mange profesjonelle kodere.

Før vi kan bruke Sinatra skal det installeres. Åpne et kommandovindu og skriv:

$ gem install sinatra -v 1.3

PS: $ tegnet skal ikke skrives.

Det neste vi skal gjøre er å lage følgende mappestruktur:

├── kidsbook.rb
├── public
│   ├── kidsbook.html
│   ├── login.html
│   ├── kidsbook.css
│   └── kidsbook_logo.png
└── views
    └── (foreløpig tomt)

Filen `kidsbook.rb` skal være hovedfilen vår. Vi oppretter den med innholdet:

require 'sinatra'

Hvis du nå kjører scriptet starter web serven. Du kan koble til siden din på adressen http://localhost:4567/kidsbook.html

http://localhost:4567/kidsbook.html

Vi sier her at vi kjører mot vår egen maskin på port 4567. Når vi erstatter `localhost` med din ip adresse kan man lese siden fra en annen maskin.

Dynamiske web sider

Sinatra serveren kan gjøre mer enn å gi ut filer fra disken. La oss lage en side med tilfeldige tall.

Modifiser `kidsbook.rb` filen slik, og restart serveren. Du må trykke Ctrl+C for å avslutte den som allerede kjører.

require 'sinatra'

get '/tilfeldig' do
  tall = rand(0..9999)
  tall.to_s             # vi må alltid gi tilbake en streng
end

Se hva som skjer når du går inn på http://localhost:4567/tilfeldig

Oppgave: Adressekorter

`bit.ly` er et eksempel på en web side som lager en kort adresse som videresender deg til en annen side med en lengre adresse. Lag en egen slik web side. For å sende videre til en annen adresse bruk koden:

require 'sinatra'

get '/a' do
  redirect to("http://www.google.com/")
end

Layout

Da vi laget en side for startsiden og en for innlogging la du kanskje merke til at det var en del av HTML kodene som var like (dvs alt untatt hoveddelen). Vi skal nå fikse opp i dette.

Første steg skal være å flytte

public/index.html

til

views/index.erb

Neste steg er å legge til følgende kode i kidsakoder.rb

get '/' do
  erb :index
end

Det vi nå sier er at sinatra skal gi ut filen index.erb dynamisk istedet for å gi ut en statisk fil fra disken

Adressen '/' angir den siden man kommer til når adresselinjen kuninneholder maskinnavn og port.

Så kopierer vi views/index.erb til views/layout.erb, og sletter detmidterste som ikke er felles. Det skal se omtrent slik ut:

<!DOCTYPE html>
<html>
  <head>
    <title>Kidsbook</title>
    <link rel="stylesheet" type="text/css" href="kidsbook.css">
  </head>
  <body>
    <img src="kidsbook_logo.png"></img>
    <%= yield %>
  </body>
</html>

Vi erstattet delen i midten med `yield`

Til slutt gjør vi motsatt for filen views/index.erb, som skal se slikut


Trykk her for å logge inn.


Dette skal bli et innlegg

Hilsen: Legolas

Oppgave: Layout

Lag et layout for din indeks og innloggingssside.

Dag 4 - Webserveren

Why's Ruby Book

Tilgang fra andre maskiner

Sinatra starter vanlig utviklingsmodus med begrenset tilgang. For å åpne opp for tilgang fra andre maskiner, kan vi legge til følgende kode i kidsbook.rb:

# i filen kidsbook.rb
require 'sinatra'
set(:bind, "0.0.0.0")
...

Hver gang vi endrer på koden i kidsbook.rb, trenger vi å restarte web servern vår.

Endringer i filer i views katalogen oppdateres automatisk

Login

Vi skal implementere en enklest mulig påloggingsfunksjon.

Før vi går videre, skal alle ha kommet så langt:

  • alle .html filene har fått navn .erb og blitt flyttet til views
  • alle .erb filene skal bruke layout.erb
  • en side for index og en for login
  • en linje 'get' for hver av de to sidene i kidsbook.rb

Pålogging som vi skal lage er veldig enkel. Det holder å

  • å skrive inn navnet
  • og så trykke på ok

Alle får tilgang.

Tidligere prøvde vi å logge inn med html filen fra disk. Da fikk vi trøbbel når vi trykket på knappen.

Nå kan vi la Sinatra håndtere dette

Legg til følgende kode nederst i kidsbook.rb

post '/behandle-login' do
  p params            # skriv ut skjema data
  redirect to("/")    # omdiriger til startsiden
end

Prøv å logg inn nå og se hva som kommer ut i terminalvinuet.

Vi har nå en måte å få tak i navnet til brukeren vår. For å lagre dette skal vi bruke en kjeks (cookie).

Kjeksen er en liten datapakke som følger brukerens trafikk frem og tilbake

Når vi bruker kjeks lagres ingen informasjon i sinatra

Siden kjeksen blir sendt frem og tilbake skal vi passe på at den ikke inneholder store datamengder.

Faktisk er hver kjeks begrenset til 4 kilobyte

Ok, la oss lage kjeksen!

Start med å skru på kjeks i Sinatra

enable(:sessions)
set(:session_secret, '--__KIDSAKODER__--')

Følg opp med å endre post koden til dette:

post '/behandle-login' do
  session[:avsender] = params[:avsender]
  redirect to("/")   
end

Og for å se om vår session er blitt satt kan vi endre indeks metoden vår slik

get '/' do
  p session
  erb :index
end

Kjør koden og se at vi nå holder styr på avsenderen


Frivillig oppgave: Lag en link for å logge ut. Det greieste er å sette session[:avsender] til nil

ERB

Det neste vi ønsker å gjøre er å endre layout slik at man får enten en link til pålogging, eller teksten 'Velkommen Tenderlove!'

ERB er en måte å blande Ruby kode med HTML.

<% if session[:avsender] %>
  Trykk <a href="/ny">her</a> for å skrive et nytt innlegg
<% else %>
  For å skrive innlegg må man være logget inn.
  Trykk <a href="/login">her</a> for å logge inn.
<% end %>

Erb kommer i to varianter

<% if 1 > 10 %>
  <p>Verden går under!</p>
<% end %>

kode inne i slike bli kjørt i stillhet

Erb kommer i to varianter

Svaret er: <%= 1000 + 1000 %>

kode inne i slike skriver ut resultatet av Ruby koden

Oppgaver

  • lag en topptekst på startsiden som enten ber deg logge inn, eller lar deg poste nye innlegg
  • se om du kan finne ut forskjellen på get og post
  • lag et skjema for å skrive nye innlegg på en egen side
  • lag en ny Sinatra metode som håndterer nye innlegg

Arbeidsdeling

Siden ERB filene allerede er ganske komplekse, forsøker vi å legge mest mulig kode i Ruby filen vår (kidsbook.rb)

Vi kan sende @variable fra .rb filen til .erb filen

get '/' do
  @avsender = session[:avsender]
  erb :index
end

...sammen med .erb filen...

<% if @avsender %>
  Trykk <a href="/ny">her</a> for å skrive et nytt innlegg
<% else %>
  For å skrive innlegg må man være logget inn.
  Trykk <a href="/login">her</a> for å logge inn.
<% end %>

Fler oppgaver

  • Utvid pålogging med passord og lagre passordene i en fil

Dag 5 - En ferdig kidsbook

@codinghorror: Everyone is like whee fun programming! What they don't tell you is that your computer is a total asshole.

Egne metoder

Vi bruker metoder til å gruppere kodebiter for bedre oversikt og for å slippe å kopiere tekst.

Vi definerer og bruker en metode slik:

def pluss_sammen(a, b, c)
  a + b + c
end
> pluss_sammen(1, 2, 3)
=> 6
> pluss_sammen(4, 5, 6)
=> 15

Lagring av innleggene

Vi skal skrive en kode som skal lagre alle innleggene til fil, og lese de tilbake

Det finnes mange muligheter til å lagre innleggene. Vi skal bruke en metode som er innebygd i Ruby. Koden for å skrive ser da omtrent slik ut:

require 'yaml/store'
LAGRING = YAML::Store.new "lagring.yaml"
LAGRING.transaction do
  LAGRING[:mine_data] = ["her", "er", "mine", "data"]
end

Ved å bruke dette biblioteket slipper vi å tenke på linjeskift og slikt. Det vi legger inn på en nøkkel vil være det samme som vi henter ut

Etter å ha kjørt koden vil dette være innholdet i filen `lagring.yaml`:

---
:mine_data:
- her
- er
- mine
- data

Når vi skal lese tilbake innholdet kjører vi denne koden:

require 'yaml/store'
LAGRING = YAML::Store.new "lagring.yaml"
LAGRING.transaction do
  LAGRING.fetch(:mine_data, "denne verdien om nøkkelen ikke fins")
end
=> ["her", "er", "mine", "data"]

Oppgave: lagre innleggene

Legg til posting av innlegg og lagring til fil i kidsbook.rb. For å få det til skal dere kikke på løsningsforslaget og kopiere over den koden dere trenger til ditt eget prosjekt.

Løsningsforslag for kidsbook.rb

Oppgave: skriv ut alle innleggene på startsiden

For å skrive ut alle innleggene, sender vi dem til erb filen fra kidsbook.rb via en @variabel.

get '/' do
  @innlegg = les_alle_innlegg
  erb :index
end

...og...

<% @innlegg.each do |et_innlegg| %>
  <p class="innlegg-tekst">
  <%= et_innlegg[:tekst] %>
  </p>
  <p class="avsender">
  Hilsen: <%= et_innlegg[:avsender] %>
  </p>
<% end %>

Løsningsforslag for views/index.erb

Hva nå?

Raspberry Pi

  • Kan stå på hele tiden
  • Kjører Linux og Ruby (og kidsbook.rb)
  • Pris 400,-
  • Kan overvåke og styre elektronikk

Andre språk

Det finnes heldigvis og beklageligvis veldig mange forskjellige programmeringsspråk. Jeg skal gå gjennom noen synspunkter på de vanligste språkene.

(mer info om språk her)

C og C++

  • Raskest ytelse
  • Tar lang tid å lære seg godt (spesielt C++)
  • Størst utbredelse og derfor finner du alltid de bibliotekene du trenger
  • Førstevalget for spill
  • Programmene kan 'kræsje'
  • Kompleks minnehåndtering
  • Kjører på alle platformer, men separat kode for hver platform
  • Mange mange linjer kode

Java

  • Kjører på alle platformer (Linux, OS-X, Windows) uten endring i koden
  • Veldig utbredt, mange biblioteker
  • Ganske lett å komme igang med
  • Koden er litt kjedelig, og ganske mange linjer
  • Brukeren må installere riktig Java
  • Middels i alt
  • Brukes på Android

C#

  • Kjører bare på Windows/Windows Phone
  • Ligner mer på 'vanlig' Windows enn Java gjør
  • Ganske lett å komme i gang med
  • Godt utvalg i biblioteker
  • Tett knyttet mot Microsoft som vil tjene penger på dette
  • En kopi av Java for Windows

Javascript

  • Eneste språket som kjører internt i nettleseren
  • Enkelt å lære
  • Mange spesielle måter å løse ting på
  • Mange ting (som f.eks. gets) er veldig vanskelig å få til
  • Brukes mer og mer på server siden
  • En del suspekte designvalg som vil overraske deg

Ruby

  • Enkelt og oversiktig språk
  • Ofrer hastighet for enkelhet
  • Trenger ikke kompileres
  • Språket har mange avanserte muligheter
  • Brukes mye på server siden, spesielt web
  • Lite støtte for å lage vanlige programmer
  • Knyttet mest til Linux/OS-X verden
  • Brukeren må installere Ruby
  • Innovativt utviklermiljø

Python

  • Enkelt og oversiktig språk
  • Ofrer hastighet for enkelhet
  • Trenger ikke kompileres
  • Språket har få avanserte muligheter for å holde det enkelt
  • Noe større støtte i biblioteker enn Ruby
  • Brukeren må installere Python
  • Innovativt utviklermiljø

Apple Swift

  • Kun for iPhone, iPad og OS-X
  • Ligner litt på Ruby
  • Veldig nytt, så fremtiden er uviss
  • Betenkelig ytelse og robusthet
  • Vil bli bedre med tiden

Google Go

  • Ligner mest på en enklere utgave av C
  • Man trenger ikke installere noe utover programmer du lager
  • Bedre støtte for å kjøre ting samtidig enn C

Haskell, Erlang, Elixir, Lisp, Scala, Clojure, F#

  • Veldig avanserte språk
  • Veldig interessante om man er opptatt av sånt
  • Løser noen problemer veldig bra
  • Lite brukt, men det finnes noen hederlige unntak
  • Innovativt utviklermiljø

Slutt

Oppgaver

  • Utvid kidsbook.rb med en 'Like' knapp
  • Pålogging med passord i tillegg til navn
  • Utveksling av innlegg mellom maskinene (kidsbook til kidsbook)