Methoden & Keyword-Args
Ruby-Methoden: Parameter, Default-Werte, Keyword-Arguments, Splat und Double-Splat. Plus Blocks, yield und die Konvention der ?/!-Methoden.
Inhaltsverzeichnis
Methoden & Keyword-Args in Ruby
Methoden sind in Ruby extrem flexibel - mit Keyword-Arguments, optionalen Parametern und Blocks gibt es viele Wege, eine API zu designen.
Grundform
def gruessen(name)
"Hallo, #{name}!"
end
puts gruessen("Anna")
def ... endstatt{...}- Kein
returnnoetig - der letzte Ausdruck ist der Rueckgabewert snake_caseist Konvention fuer Methodennamen
Expliziter return
def sicher_teilen(a, b)
return nil if b == 0
a / b
end
return bricht die Methode sofort ab - nuetzlich fuer Guard-Clauses.
Parameter und Default-Werte
def gruessen(name, gruss = "Hallo")
"#{gruss}, #{name}!"
end
gruessen("Anna") # "Hallo, Anna!"
gruessen("Max", "Hi") # "Hi, Max!"
Keyword-Arguments
Benannte Parameter:
def gruessen(name:, gruss: "Hallo")
"#{gruss}, #{name}!"
end
gruessen(name: "Anna") # "Hallo, Anna!"
gruessen(name: "Max", gruss: "Hi") # "Hi, Max!"
name:ohne Default = pflichtgruss: "Hallo"= optional mit Default
Keyword-Arguments machen API-Aufrufe selbstdokumentierend - besonders bei mehreren Parametern:
def nutzer_anlegen(name:, email:, rolle: :user, aktiv: true)
# ...
end
nutzer_anlegen(
name: "Anna",
email: "anna@example.com",
rolle: :admin
)
Splat (*) und Double-Splat (**)
Variadic Positional: *args
def summe(*zahlen)
zahlen.sum
end
summe(1, 2, 3) # 6
summe(1, 2, 3, 4, 5) # 15
# Array entpacken
arr = [10, 20, 30]
summe(*arr) # 60
Variadic Keyword: **kwargs
def config(**options)
options.each { |k, v| puts "#{k} = #{v}" }
end
config(port: 3000, host: "localhost", debug: true)
Kombiniert
def flexibel(name, *positional, key: "default", **rest)
# name: pflicht, positional
# positional: beliebig viele positional args
# key: keyword mit default
# rest: weitere keywords
end
Block-Argumente
Jede Methode kann einen Block empfangen - das ist ein zentrales Ruby-Konzept:
def dreimal
yield
yield
yield
end
dreimal { puts "Hallo!" }
# Hallo!
# Hallo!
# Hallo!
yield ruft den uebergebenen Block auf.
Block mit Argumenten
def mit_zahlen
yield 1
yield 2
yield 3
end
mit_zahlen { |n| puts n * 10 }
# 10, 20, 30
Optionaler Block
def eventuell
if block_given?
yield "wurde aufgerufen"
else
"kein Block"
end
end
eventuell # "kein Block"
eventuell { |t| puts t } # "wurde aufgerufen"
Block als Parameter
Mit &block fangst du ihn als Proc:
def zweimal(&block)
block.call
block.call
end
zweimal { puts "Hallo" }
Rueckgabewerte
def position(liste, wert)
liste.each_with_index do |e, i|
return i if e == wert
end
nil
end
puts position([10, 20, 30], 20) # 1
puts position([10, 20, 30], 99) # (nil)
Mehrere Rueckgabewerte
def min_max(zahlen)
return zahlen.min, zahlen.max
end
kleinste, groesste = min_max([3, 1, 4, 1, 5, 9, 2])
puts "#{kleinste} .. #{groesste}" # 1 .. 9
Ruby gibt ein Array zurueck, die Destrukturierung nimmt es auseinander.
Konventionen: ? und !
Ruby erlaubt ? und ! am Ende von Methodennamen - reine Konvention, aber sehr aussagekraeftig:
? - gibt Boolean zurueck
[].empty? # true
"hallo".include?("all") # true
42.even? # true
! - “gefaehrlich” oder “modifiziert in-place”
str = "hallo"
str.upcase # "HALLO" - neues Objekt
str # "hallo" - unveraendert
str.upcase! # modifiziert str direkt
str # "HALLO"
Oder: “wirft Exception statt nil zurueckzugeben”:
arr = [1, 2, 3]
arr.first # 1 (nil wenn leer)
arr.first! # (gibt es so nicht, nur Beispielkonvention)
User.find(1) # findet oder nil
User.find!(1) # findet oder raise (ActiveRecord)
Methoden als Werte
Methodenreferenz mit method:
def verdoppeln(n)
n * 2
end
m = method(:verdoppeln)
puts m.call(5) # 10
Oder als Proc weiterreichen:
[1, 2, 3].map(&method(:verdoppeln)) # [2, 4, 6]
Symbol-to-Proc: &:methode
Ein Ruby-Klassiker:
namen = ["max", "anna", "leo"]
# Lang:
namen.map { |n| n.upcase }
# Kurz:
namen.map(&:upcase)
# ["MAX", "ANNA", "LEO"]
Das &:symbol erzeugt einen Proc, der die Methode aufruft.
Praktisches Beispiel
def nutzer_formatieren(name:, alter: nil, rollen: [], &formatter)
info_teile = [name]
info_teile << "#{alter} Jahre" if alter
info_teile << rollen.join(", ") unless rollen.empty?
text = info_teile.join(" - ")
formatter ? formatter.call(text) : text
end
puts nutzer_formatieren(name: "Anna", alter: 28, rollen: [:admin])
# Anna - 28 Jahre - admin
puts nutzer_formatieren(name: "Max") { |t| "[#{t.upcase}]" }
# [MAX]
Zusammenfassung
def ... end, snake_case, letzter Ausdruck ist Rueckgabewert- Default-Werte (
parameter = wert) und Keyword-Args (key: default) *argsfuer variadic,**kwargsfuer keyword-variadic- Blocks via
yieldoder&block- fundamental im Ruby-Alltag ?-Methoden fuer Booleans,!-Methoden fuer destruktive Aktionen&:methodeals kompakte Block-Form (map(&:upcase))
Im naechsten Kapitel: Klassen, Blocks und das Enumerable-Modul - Rubys OOP-Herzstueck.