Kurz: begin puts teile(10, 2) puts teile(1, 0) rescue ZeroDivisionError => e puts “Fehler: #{e.message}” else puts “kein Fehler” ensure puts “ensure läuft immer” end
Teil des Kurses Ruby
Exceptions
def teile(a, b)
raise ZeroDivisionError, "Division durch null" if b.zero?
a / b
end
begin
puts teile(10, 2)
puts teile(1, 0)
rescue ZeroDivisionError => e
puts "Fehler: #{e.message}"
else
puts "kein Fehler"
ensure
puts "ensure läuft immer"
end
def versuche
yield
rescue TypeError, ArgumentError => e
puts "#{e.class}: #{e.message}"
end
versuche { Integer("x") }
versuche { 1 + nil }
versuche { [1, 2].fetch(9) } rescue puts "IndexError (Modifikator-rescue)"
puts (Integer("zzz") rescue -1)
versuche = 0
begin
versuche += 1
raise "kaputt" if versuche < 3
puts "klappte im Versuch #{versuche}"
rescue
retry # erneut versuchen
endAusgabe:
5
Fehler: Division durch null
ensure läuft immer
ArgumentError: invalid value for Integer(): "x"
TypeError: nil can't be coerced into Integer
IndexError (Modifikator-rescue)
-1
klappte im Versuch 3Fehlerklassen bilden eine Hierarchie: Exception > StandardError > ArgumentError, TypeError, NameError, ZeroDivisionError, IOError … rescue ohne Klasse fängt StandardError. Fange nie Exception pauschal.
class AppFehler < StandardError; end
class NichtGefunden < AppFehler
def initialize(was) = super("#{was} nicht gefunden")
end
begin
begin
raise NichtGefunden, "Nutzer 7"
rescue AppFehler => e
raise RuntimeError, "umgepackt" # Ursache wird automatisch gemerkt
end
rescue => e
puts "#{e.message} <- #{e.cause.class}: #{e.cause.message}"
end
x = catch(:fertig) do
10.times { |i| throw :fertig, i if i == 3 }
:nie
end
puts xAusgabe:
umgepackt <- NichtGefunden: Nutzer 7 nicht gefunden
3Dateien
require "tmpdir"
Dir.mktmpdir do |dir|
pfad = File.join(dir, "demo.txt")
File.write(pfad, "Zeile 1\nZeile 2\n")
File.open(pfad, "a") { |f| f.puts "Zeile 3"; f.print "Zeile 4\n" }
puts File.read(pfad).length
p File.readlines(pfad, chomp: true)
File.foreach(pfad) { |z| print z.length, " " }
puts
File.open(pfad) do |f|
puts f.gets
puts f.readline
p f.eof?
end
p File.exist?(pfad), File.file?(pfad), File.directory?(dir), File.size(pfad)
p File.basename(pfad), File.extname(pfad), File.basename(pfad, ".txt"), File.dirname("/a/b/c.rb")
Dir.mkdir(File.join(dir, "unter"))
File.write(File.join(dir, "unter", "x.rb"), "")
p Dir.glob("**/*", base: dir).sort
File.delete(pfad)
p File.exist?(pfad)
endAusgabe:
32
["Zeile 1", "Zeile 2", "Zeile 3", "Zeile 4"]
8 8 8 8
Zeile 1
Zeile 2
false
true
true
true
32
"demo.txt"
".txt"
"demo"
"/a/b"
["demo.txt", "unter", "unter/x.rb"]
falseDas Block-Muster (File.open(...) { |f| ... }) schließt die Datei automatisch.
JSON, CSV und YAML
require "json"
require "csv"
require "yaml"
daten = { "name" => "Mia", "alter" => 17, "hobbys" => ["Lesen", "Judo"], "adresse" => nil }
json = JSON.generate(daten)
puts json
puts JSON.pretty_generate(daten)
zurueck = JSON.parse(json)
puts zurueck["hobbys"][1]
sym = JSON.parse(json, symbolize_names: true)
puts sym[:name]
begin
JSON.parse("{kaputt")
rescue JSON::ParserError
puts "ungültiges JSON"
end
puts [1, "a", nil, true].to_json, { a: 1 }.to_json
csv = "name,punkte\nMia,120\nTom,80\n"
tabelle = CSV.parse(csv, headers: true)
tabelle.each { |z| puts "#{z['name']}: #{z['punkte']}" }
puts CSV.generate { |c| c << ["x", "a,b"]; c << [1, 2] }
puts({ "titel" => "Test", "liste" => [1, 2] }.to_yaml)
p YAML.load("a: 1\nb:\n - x\n - y\n")Ausgabe:
{"name":"Mia","alter":17,"hobbys":["Lesen","Judo"],"adresse":null}
{
"name": "Mia",
"alter": 17,
"hobbys": [
"Lesen",
"Judo"
],
"adresse": null
}
Judo
Mia
ungültiges JSON
[1,"a",null,true]
{"a":1}
Mia: 120
Tom: 80
x,"a,b"
1,2
---
titel: Test
liste:
- 1
- 2
{"a"=>1, "b"=>["x", "y"]}Reguläre Ausdrücke
text = "Mia (mia@example.com) und Tom (tom@test.de)"
p text =~ /\w+@\w+\.\w+/
p text.scan(/\w+@\w+\.\w+/)
if (m = text.match(/(?<name>\w+) \((?<mail>[^)]+)\)/))
puts "#{m[:name]} -> #{m[:mail]}"
end
p "2025-03-15".match?(/\A\d{4}-\d{2}-\d{2}\z/)
puts "a1b22c333".gsub(/\d+/) { |z| "<#{z.length}>" }
puts "Hallo Welt".sub(/(\w+) (\w+)/, '\2 \1')
p "a, b;c".split(/[,;]\s*/)
p $~.nil?, "x" !~ /y/
if "Datum: 15.03.2025" =~ /(\d+)\.(\d+)\.(\d+)/
puts "#{$3}-#{$2}-#{$1}"
endAusgabe:
5
["mia@example.com", "tom@test.de"]
Mia -> mia@example.com
true
a<1>b<2>c<3>
Welt Hallo
["a", "b", "c"]
true
true
2025-03-15Zeit und Datum
require "time"
require "date"
t = Time.utc(2025, 3, 15, 14, 30, 0)
puts t, t.year, t.strftime("%d.%m.%Y %H:%M"), t.wday, t.yday, (t + 86400).day
puts Time.parse("2025-03-15 10:00:00 UTC").hour
d = Date.new(2025, 3, 15)
puts d + 20, d >> 1, d.saturday?, d.strftime("%A"), (Date.new(2025, 12, 24) - d).to_i
puts Date.valid_date?(2025, 2, 30), Date.leap?(2024)Ausgabe:
2025-03-15 14:30:00 UTC
2025
15.03.2025 14:30
6
74
16
10
2025-04-04
2025-04-15
true
Saturday
284
false
trueMerke
begin / rescue / else / ensure / end,raise,retry; eigene Fehlerklassen vonStandardError- Dateien:
File.read/write/open/foreach, Block schließt automatisch json,csv,yamlgehören zur Standardbibliothek- Reguläre Ausdrücke:
=~,match,scan,gsubmit benannten Gruppen TimeundDatefür Zeitrechnung
Übungsaufgabe
Lies eine CSV mit Namen und Punkten, berechne den Durchschnitt und schreibe das Ergebnis als JSON.
Quiz zur Selbstkontrolle
Was fängt ein nacktes rescue ab?
- StandardError und Unterklassen (richtig)
- Jede Exception inklusive Exit
- Nur ArgumentError
- Nichts
Warum nutzt man File.open mit Block?
- Die Datei wird automatisch geschlossen (richtig)
- Es ist schneller
- Es ist Pflicht
- Es erlaubt mehrere Dateien
Welche Methode liest JSON-Text in einen Hash?
- JSON.parse (richtig)
- JSON.load_file
- to_json
- JSON.stringify
Weiter im Kurs
Zurück: Module, Mixins und Enumerable
Weiter: Metaprogrammierung und Ruby-Idiome
Alle Kapitel: Ruby im Überblick