---
theme: gaia
paginate: true
title: Ruby-Schulung Linuxhotel Oktober 2026
---
<style>
  section {
    background: #fefefe;
    color: #004;
  }
  section.invert {
    background: #004;
    color: #fefefe;
  }

  section.lead h1 {
    font-size: 4em;
  }

  section.small p, section.small li {
    font-size: 0.6em;
  }

  section marp-pre {
    background: #002;
    border-radius: 5px;
  }

  section code {
    background: #002;
    border-radius: 5px;
  }

</style>

# Willkommen zur
## Ruby-Schulung
## im Linuxhotel
### 12.10.2026

---
<!-- class: lead invert -->
# Vorstellung

---
<!-- class: -->
# Jan Krutisch

- Freier Software-Entwickler und [Gründer](https://depfu.com)
- Hamburg
- Ruby/ Rails seit 2005
- Projekte in allen Formen und Farben

---

# Jetzt Ihr

- Name
- Vorkenntnisse (Auch: Andere Programmiersprachen)
- Kursziele, ggf. Anwendungsfeld

---

# Was uns erwartet

- 5 volle Tage
- Viel Praxis, viel Pausen
- Viele Fragen, bitte!

---

# Das wichtigste

- Editor der Wahl
- Das Pad

---

# Themen (Grob)

1. Tag: Einführung, Installation, Grundlagen
2. Tag: Fortsetzung, der Kern von Ruby
3. Tag: Objektorientierung
4. Tag: Die Standard-Library, Rubygems, das Web
5. Tag: This page intentionally left blank

---

# Try Ruby & Registrierung

- https://try.ruby-lang.org/
- Registrierung für lab.linuxhotel.de
---

# ...

---
<!-- class: lead invert -->
# Ruby

---
<!-- class: -->
# Ruby
## Entwickelt von Yukihiro "Matz" Matsumoto ab 1995
## Bekannt in Europa und USA seit ca. 2002
## Große Popularität im Westen dank Ruby on Rails ab 2004/ 2005
---

# Design-Goals:
- Developer Happiness
- Von Beginn an Objektorientiert
- Ideen aus Perl, Lisp und Smalltalk

---

# Offizielle Implementierung:
## MRI ("Matz' Ruby-Interpreter")

---

# Diverse andere Implementierungen:
## JRuby (JVM)
## TruffleRuby
## DragonRuby
## mruby
## ...

---

# Ruby ist...
## ...objektorientiert
## ...elegant
## ...lesbar
## ...schön?

---

# Beispiele

```ruby
3.times do
  print "Welcome"
end
```

```ruby
20.days.from_now
# (Nicht wirklich ruby)
```

---

# Installation

---

# Viele Wege führen nach Rom

---

# Windows

## https://rubyinstaller.org/

---

# Mac

## homebrew

---

# Linux

## Paketmanager

## Aber!

---

![w:800](images/ruby-on-ubuntu-lts.png)

# vs.

![w:800](images/ruby-release-schedule.png)

---

# Generic Version Managers
## asdf, mise, proto, aqua

# Ruby Version Managers
## rbenv, rvm

---

# New kid on the block

## rv

---

# Für heute:

```bash
mise install ruby@3.4.10
mise use ruby@3.4.10
```

---

# `hello_world.rb`

```ruby
#!/usr/bin/env ruby
puts "Hello World"
```

---
# Anatomie eines Ruby-Skripts
- "shebang" `#!/usr/bin/env ruby`
- Einrückung: 2 Leerzeichen
- Nicht vergessen: `chmod +x`
- Kommentare starten mit # (wie bash, python etc.)

---

# Über Ruby aufrufen

(Dann kein shebang nötig)

`$ ruby script.rb`

---

# Zeichenkodierung

- UTF-8 hat gewonnen (Code ist UTF-8 per default, seit Ruby 2.0.0)
- Strings haben eigenes encoding (UTF-8 in meisten Fällen default)
- Umfangreiche Funktionen für Transcoding

---

# Syntax

---

# Eine Anweisung pro Zeile, ohne zwingendes Semikolon

```ruby
puts "Eins"
puts "Zwei"
```
---

# Semikolons können verwendet werden, sehr unüblich

```ruby
puts "Eins"; puts "Zwei"
```
---

# IRB

`$ irb`

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)
# Praxis



---
<!-- class: -->
# Erste Schritte

- Schreibe ein Programm, das auf drei getrennten Zeilen auf der Konsole eine Ausgabe macht.
- Führe das Programm testweise in der Konsole aus.
- Lade Dein Programm in der IRB mit Hilfe von require hinzu. Was passiert?

---

# Variablen

## Lokale Variable

```ruby
a = 1
```

---

# Variablen

- Muss mit kleinem Buchstaben anfangen (Ausnahmen!)
- Üblich: snake_case
- Möglich: Fast alles (`🎂 = "lie"`)
- Keine Deklaration
- Keine Typdeklaration
---

# Konstanten

```ruby
EPOCH_YEAR = 1970
```

---

# Konstanten
- Sind nicht konstant
- Müssen mit großem Buchstaben anfangen
- Üblich: SNAKE_CASE
- Auch hier: Emojis sind möglich

---

# Globale Variablen

```ruby
$foo = "bar"
```

---

# Globale  Variablen

- Nein
- Nein
- Nein

---

# Datentypen

---

# Literale

```ruby
nil                         # Nichts
1, 300_000, 3.14, 2.4e-20   # Zahlen
'hallo', "hallo", %q(hallo) # Zeichenketten
:status, :through           # Symbole
true, false                 # Wahrheitswerte
10..20, 10...20, 'a'..'z'   # Bereiche
/pattern/, /^\d+/           # Reguläre Ausdrücke (Regexp)
```

---

# Zeichenketten

```ruby
a = 'aha'
b = "soso"
b = "jaja\nnundenn"
c = "->#{b}<-"
d = %Q("#{a}")
```
---

# Symbole
- Global einmalig
- unveränderbar
- Parameter, Konfiguration, etc. etc.

---
# Alles ist ein Objekt
```ruby
true.class # => TrueClass
2.class    # => Integer
2.2.class  # => Float
"hello".class # => String
```

---

# Alles ist ein Objekt
- Datentypen sind Klassen
- Werte sind Objekte dieser Klassen
- Weitgehende Introspektion (`2.class.superclass # => Numeric`)

---

# Objekte haben Methoden

```ruby
5.next              # 6
'hallo'.length      # 5
'hallo'.chop        # "hall"
:name.is_a? Symbol  # true
```

---

# Klammern um Argumente?

```ruby
'hallo'.length()
:name.is_a?(Symbol)
```

---

# Typ-Umwandlung

```ruby
23.to_s    # "23"
"42".to_i  # 42
"42".to_f  # 42.0
"3.3".to_f # 3.3
"abc".to_i # 0
```
---

# Aha!

```ruby
23.to_s(16)    # "17"
"abc".to_i(16) # 2748
```

---

# "Globale" Methoden

(Dokumentation: [Kernel](https://ruby-doc.org/4.0.6/Kernel.html))

```ruby
puts "Hallo" # Zeile ausgeben

a = gets     # Zeile einlesen
```

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)
# Praxis

---
<!-- class: -->
# Nachfolger

Schreibt ein Programm, das den Benutzer auﬀordert, eine Ganzzahl einzugeben.
Anschließend soll das Programm den Nachfolger dieser Ganzzahl ausgeben.

---

# Operatoren


```ruby
5 + 1               # 6
5 / 2               # 2 (Achtung!)
5.0 / 2.0           # 2.5
"Hello" + " World"  # "Hello World"
true && true        # true
true and false      # false
true || false       # true
false or true       # true
!true               # false
not false           # true
```

---

---
# Kurzformen

Aus Operator und Zuweisung lassen sich Kurzformen
bilden

```ruby
a = a + 1
a += 1
a ||= 5
a = a || 5
```

---
# Eigene Methoden Definieren

```ruby
def add(a, b)
  return a + b
end
```
---
# Methoden
- Benennung wie lokale Variablen
- Zusätzlich gewisse Sonderzeichen erlaubt
- Beliebige Anzahl Parameter möglich

---
# Sonderzeichen in Methodennamen

```ruby
  full? # Wahrheitswert erwartet
  reset! # Seiteneffekte, In-Place, Achtung!
```
---
# Zuweisungen/ "Attribute"
```ruby
  car.plate=("XUF 203")
  car.plate = "XUF 203"
  puts car.plate()
  puts car.plate
```
---

# Operatoren
```ruby
def +(b)
  # ...
end

2.+(3)
2 + 3

```
---

# Default-Parameter

```ruby
def add(a, b = 1)
  return a + b
end
add(3)    # 4
add(3, 5) # 8
```
---

# Benannte parameter
## ("keyword args")

```ruby
def format_currency(amount:, currency: 'EUR')
  formatted_amount = sprintf('%.2f', amount)
  "#{formatted_amount} #{currency}"
end
format_currency(amount: 23) # 23.00 EUR
format_currency(currency: '$', amount: 6) # 6.00 $
```

---

# Rückgabewerte

```ruby
def add(a, b) # "Ruby Style"
  a + b
end

def add(a, b) # explizit
  return a + b
end
```

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)
# Praxis

---
<!-- class: small -->
# Hello World & Quadratzahlen

Schreibt eine hello-world-Methode, die einen
personalisierten Gruß ausgibt. Dazu soll ein Parameter
“name” übergeben werden. Anschließend soll der Gruß
“Hallo <name>” ausgegeben werden, wobei <name>
durch den übergebenen Namen ersetzt wird.

Schreibt eine Methode, um Quadratzahlen zu berechnen.
Als Parameter soll eine Zahl übergeben werden.
Rückgabewert soll das Quadrat der Zahl sein.
Schreibt jeweils einen Aufruf der Methode, der die
Funktionsweise testet und das Ergebnis auf der Konsole ausgibt.


---
<!-- class: -->
# Kontrollstrukturen

---
# Fallunterscheidungen

```ruby
if a > 1000
  puts "zu groß"
elsif a == 23
  puts "nicht erlaubter Wert"
else
  puts "korrekte Eingabe"
end
```
---

# Kompakte version

```ruby
  puts "OK" if a == 23
```
---
# Ternär

```ruby
(a == 2) ? "zwei" : a.to_s
```
---
# Unless

```ruby
return 20 unless status == 200
```

---

# Unless

- Eignet sich gut für "Guards"
- Bitte nicht:
  - Mit komplexen boolschen Ausdrücken (Knoten im Kopf garantiert)
  - Mit else kombinieren

---


# Bedingungen

Beliebige Ruby-Ausdrücke können als Bedingungen
benutzt werden
- `true` ist wahr
- `false` ist unwahr
- `nil` ist unwahr
- Alles andere (auch `0`, `""` etc.) ist wahr
- Kombination mit `&&` und `||` und `!`
- (Theoretisch auch mit `and` und `or` und `not`)
- Klammern nur für Präzendenz.

---

# Alles ist ein Ausdruck

```ruby
a = if b == 1
  'Eins'
elsif b == 2
  'Zwei'
else
  b.to_s
end
```
---

# Und wenn dann?!?

```ruby
a = if false
  'Falsch'
end

# => a = nil
```

---
# Vergleiche

```ruby
2 == 2          # true
3 == 3.0        # true
3.equal? 3.0    # false

2 != 3          # true
3 > 2           # true
```

---
# Fallunterscheidungen

```ruby
case a
when 1
  'Eins'
when 2
  'Zwei'
else
  a.to_s
end
```
---

# Fallunterscheidungen

```ruby
case var
when Fixnum, Float
  'Zahlwert'
when String
  'Zeichenkette'
else
  'Unbekannter Datentyp'
end
```
---
# Drei =

```ruby
4 === 4         # true
Integer === 4   # true
2 === 2.0       # true
4 === Integer   # false
```

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)

# Praxis
---
<!-- class: -->
# Taschenrechner

Schreibt ein Taschenrechnerprogramm, das den Nutzer
nacheinander auﬀordert eine Zahl, einen Operator und
dann noch eine Zahl einzugeben.
Das Programm soll anhand des Operators die passende
Rechnung mit den beiden Zahlen durchführen und das
Ergebnis ausgeben.

---
# Schleifen
```ruby
loop do
  puts "I WON'T STOP!"
end
```
---
# Mehr Schleifen

```ruby
while true
  puts "Do something"
end

until false
  puts "Do something"
end
```

---

# Kontrolle
```ruby
loop do
  next if something?  # nächste iteration
  break if something? # exit
  redo if something?  # iteration wiederholen
end
```
---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)
# Praxis

---
<!-- class: small -->
# Ratespiel

Schreibt ein Zahlratespiel, das eine zufällige Zahl von 1 bis 10 (oder 100, oder …) auswählt und den Benutzer so lange die Zahl raten lässt, bis er korrekt geraten hat.

Bei jedem Durchlauf soll angezeigt werden, um den wievielten Versuch es sich handelt. Anschließend soll der Nutzer einen Tipp abgeben können. Das Programm gibt aus, ob der Tipp korrekt war, oder ob die gesuchte Zahl kleiner oder größer ist als der abgegebene Tipp.

Ist der Tipp korrekt, beendet sich das Programm.

Andernfalls wird wieder der Versuch angezeigt und um einen neuen Tipp gebeten. Usw.

---
# Arrays

Sortierte Liste von Werten

```ruby
a = [1, 2, 5, 6]
a[0]                            # => 1
a = ["hallo", 1, 3.8, :name]
a << 3
a.push(3)
a.pop                           # => 3
a.first                         # "hallo"
```
---

# Hashes

## "Assoziative Arrays"
## "HashMaps"
## Schlüssel/Wert-Paare

---

# Hashes

# Allgemeine Syntax

```ruby
h = {:name => "Otto Mustermann", :strasse => "Musterstraße 22", :ort => "Musterstadt"}
```

# Wenn Schlüssel Symbols sind
```ruby
h = {name: "Otto Mustermann", strasse: "Musterstraße 22", ort: "Musterstadt" }
h[:name] \# "Otto Mustermann"
```

---
# Code blocks

```ruby
loop { puts "Endlos!" }

5.times do |i|
  puts i
end
```

---
# Iteratoren

```ruby
a = [1, 2, 3]
a.each { |element| puts element }
a.each_with_index do |element, i|
  puts "#{i}. #{element}"
end
```
---
# Iteratoren

```ruby
h = {eins: 1, zwei: 2, drei: 3}
h.each_key { |key| puts key }
h.each { |key, value| puts "#{key}: #{value}" }
```


# Select & Map
```ruby
a = [1, 2, 3, 4, 5, 6]
a.select {|e| e > 3}   # [4, 5, 6]
a.map {|e| e * 2}      # [2, 4, 6, 8, 10, 12]
```
---
# API-Dokumentationen Lesen lernen

[ruby-doc.org](https://ruby-doc.org/4.0.6/)

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)

# Praxis

---
<!-- class: -->
# API-Doku lesen

- Lest die API-Dokumentation von String, Array und/oder
Hash.
- Sucht Euch eine Methode aus, die Euch interessant
erscheint und lernt ihre Funktionsweise.
- Präsentiert Eure Methode.

---
# Code blocks als objekte

- Objekte vom Typ Proc
- Erzeugen mit `Proc.new`, `proc`, `lambda` oder `->`
- `lambda` / `->`
  - parameter-checks
  - Verhalten von `return`
- `call` zum ausführen

---

# Blöcke benutzen

```ruby
def benchmark
  a = Time.now
  yield
  puts Time.now - a
end

benchmark do
  1000000.times { "23000".to_i }
end
```

---

# Block?

```ruby
def frame(content = "")
  content = yield if block_given?
  border = "-" * (content.size + 4)
  puts border
  puts "| #{content} |"
  puts border
end

frame("hallo")
frame { "zufall#{rand(1009)}" }
```

---

# Block "durchreichen"

```ruby
def twice(&block)
  2.times &block
end

twice { puts "hallo" }
```

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)
# Praxis

---
<!-- class: small -->
# Adressdatenbank

[pad neu](https://pad.halfbureau.de/pad/#/2/pad/edit/DumWdBZJLFabDZN5V95dk+EB/)

Schreibt eine Adressdatenbank. Das Programm soll Adressen, die mindestens Name, Straße und Ort enthalten im Hauptspeicher ablegen und wieder verfügbar machen.

Dazu präsentiert das Programm dem Benutzer ein Hauptmenü mit folgenden Möglichkeiten:

- Bei der Eingabe von “N” (oder “n”) wird ein neuer Datensatz angelegt. Der Benutzer wird der Reihe nach gebeten, alle erforderlichen Daten einzugeben.
- Bei der Eingabe von “L” (oder “l”) werden alle bisher eingegebenen Datensätze in verkürzter Form ausgegeben.
- Die Darstellung soll nur den Index und den Namen enthalten.
- Bei Eingabe eines gültigen Index wird der passende Datensatz vollständig angezeigt.
- Zusätzlich soll es möglich sein, das Programm zu beenden.



---
<!-- class: -->
# I/O

- `STDIN`, `STDOUT`, `STDERR`
- `puts` ist eigentlich `STDOUT.puts`
- `gets` ist `STDIN.gets`

---

# I/O-Operationen

- Zeilenweise: `gets`, `puts`
- Zeichenweise: `getc`, `putc`
- Mehr: `read`, `write`
- Gilt für Streams, Dateien, Netzwerk

---

# Dateien

```ruby
File.open("test.txt", "w") do |file|
  file.puts "Hallo"
end
```

“r“ead, “w“rite, “a“ppend (, “b“inary)

---
# Datei zeilenweise verarbeiten

```ruby
File.open("data.txt", "r") do |file|
  file.each_line do |line|
    puts line
  end
end
```

---

#  Helper

```ruby
File.exists?("/tmp/test.txt")   # false
File.basename("/tmp/test.txt")  # "test.txt"
File.dirname("/tmp/test.txt")   # "/tmp"
File.join("tmp", "test.txt")
# "tmp/test.txt"
Dir.mkdir("/tmp/testdir")
Dir.entries("/tmp")             # [...]
Dir.glob("/tmp/*.txt")          # [...]
```

---
<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)
# Praxis


---
<!-- class: -->
# Addressdatenbank die zweite

Erweitert Eure Adressdatenbank, so dass Ihr die Daten
dauerhaft abspeichern und auch wieder einlesen könnt.


