Lade den Code herunter: ruby-de.rb
# Das ist ein Kommentar
=begin
Das ist ein mehrzeiliger Kommentar.
Die Anfangszeile muss mit "=begin" beginnen
und die Endzeile muss mit "=end" beginnen.
Alternativ kannst du jede Zeile in einem
mehrzeiligen Kommentar mit dem # Zeichen beginnen.
=end
# In Ruby ist (fast) alles ein Objekt.
# Das schließt Zahlen ein...
3.class #=> Integer
# ...und Zeichenketten (Strings)...
"Hallo".class #=> String
# ...und sogar Methoden!
"Hallo".method(:class).class #=> Method
# Simple Arithmetik
1 + 1 #=> 2
8 - 1 #=> 7
10 * 2 #=> 20
35 / 5 #=> 7
2 ** 5 #=> 32
5 % 3 #=> 2
# Bitweise Operatoren
3 & 5 #=> 1
3 | 5 #=> 7
3 ^ 5 #=> 6
# Arithmetik ist aber eigentlich nur syntaktischer Zucker
# um eine Methode eines Objekts aufzurufen
1.+(3) #=> 4
10.* 5 #=> 50
100.methods.include?(:/) #=> true
## Spezielle Werte sind Objekte
nil # Equivalent zu null in anderen Sprachen
true # Wahrheitswert
false # Falschheitswert
nil.class #=> NilClass
true.class #=> TrueClass
false.class #=> FalseClass
# Gleichheit
1 == 1 #=> true
2 == 1 #=> false
# Ungleichheit
1 != 1 #=> false
2 != 1 #=> true
# Neben false selbst, ist nil der einzige andere
# zu Falsch evaluierende Wert
!!nil #=> false
!!false #=> false
!!0 #=> true
!!"" #=> true
# Weitere Vergleiche
1 < 10 #=> true
1 > 10 #=> false
2 <= 2 #=> true
2 >= 2 #=> true
# Kombinierter Vergleichsoperator (gibt `1` zurück wenn das erste Argument
# größer ist, und `-1`, wenn das zweite Argument größer ist, sonst `0`)
1 <=> 10 #=> -1 (1 < 10)
10 <=> 1 #=> 1 (10 > 1)
1 <=> 1 #=> 0 (1 == 1)
### Logische Operatoren
true && false #=> false
true || false #=> true
# Es gibt alternative Versionen der logischen Operatoren mit niedrigerer
# Wertigkeit. Diese werden meistens zur Flusskontrolle eingesetzt, um
# verschiedenen Ausdrücke zu verketten bis einer true oder false zurück
# liefert.
# `do_something_else` wird nur ausgewertet wenn `do_something` true ist.
do_something() and do_something_else()
# `log_error` wird nur ausgewertet wenn `do_something` false ist.
do_something() or log_error()
# String Interpolation
placeholder = 'Ruby'
"Ich kann in #{placeholder} Platzhalter mit doppelten Anführungszeichen füllen."
#=> "Ich kann in Ruby Platzhalter mit doppelten Anführungszeichen füllen."
# Du kannst Strings mit `+` verbinden, nicht jedoch mit anderen Typen
'hallo ' + 'Welt' #=> "hallo Welt"
'Hallo ' + 3 #=> TypeError: no implicit conversion of Integer into String
'hallo ' + 3.to_s #=> "hallo 3"
"hallo #{3}" #=> "hallo 3"
# ...oder Strings mit Operatoren kombinieren
'hallo ' * 3 #=> "hallo hallo hallo "
# ...oder Strings an andere Strings anhängen
'hallo' << ' Welt' #=> "hallo Welt"
# Du kannst Text mit einer neuen Zeile am Ende ausgeben
puts "Ich gebe Text aus!"
#=> Ich gebe Text aus!
#=> nil
# ...oder Text ohne einen Zeilenumbruch ausgeben
print "Ich gebe Text aus!"
#=> "Ich gebe Text aus!" => nil
# Variablen
x = 25 #=> 25
x #=> 25
# Beachte, dass Zuweisungen den zugewiesenen Wert zurückgeben.
# D.h. du kannst mehrfache Zuweisungen machen.
x = y = 10 #=> 10
x #=> 10
y #=> 10
# Nutze snake_case für Variablennamen.
snake_case = true
# Nutze verständliche Variablennamen.
path_to_project_root = '/guter/Name/'
m = '/schlechter/Name/'
# Symbole sind unveränderliche, wiederverwendbare Konstanten, welche intern
# als Integer repräsentiert werden. Sie werden häufig anstelle von Strings
# verwendet, um semantisch sinnvoll Werte zu übermitteln.
# Symbols werden mit dem Doppelpunkt gekennzeichnet.
:pending.class #=> Symbol
status = :pending
status == :pending #=> true
status == 'pending' #=> false
status == :approved #=> false
# Strings können in Symbole konvertiert werden und umgekehrt.
status.to_s #=> "pending"
"argon".to_sym #=> :argon
# Arrays
# Das ist ein Array.
array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
# Array können verschiedene Typen beinhalten
[1, 'hello', false] #=> [1, "hello", false]
## Arrays können indiziert werden.
# Von vorne...
array[0] #=> 1
array.first #=> 1
array[12] #=> nil
# ...oder von hinten...
array[-1] #=> 5
array.last #=> 5
# ...oder mit einem Startindex und einer Länge...
array[2, 3] #=> [3, 4, 5]
# ...oder mit einem Range...
array[1..3] #=> [2, 3, 4]
# Du kannst ein Array umkehren.
# Gib ein neues Array mit umgekehrten Werten zurück
[1,2,3].reverse #=> [3,2,1]
# Kehre ein Array an Ort und Stelle um, um die Variable mit den
# umgekehrten Werten zu aktualisieren.
a = [1,2,3]
a.reverse! #=> a==[3,2,1] wegen des Aufrufs von reverse mit Ausrufezeichens ('!')
# Wie bei der Arithmetik, ist Zugriff mit [index] nur
# syntaktischer Zucker für den Aufruf der `[]` Methode auf dem Objekt.
array.[] 0 #=> 1
array.[] 12 #=> nil
# Du kannst Werte zu einem Array hinzufügen...
array << 6 #=> [1, 2, 3, 4, 5, 6]
# Oder so
array.push(6) #=> [1, 2, 3, 4, 5, 6]
# ...und testen ob ein Element schon vorhanden ist
array.include?(1) #=> true
# Hashes sind Rubys Hauptdatenstruktur for Schlüssel/Wert Paare.
# Hashes werden durch geschweifte Klammern gekennzeichnet.
hash = { 'Farbe' => 'grün', 'Nummer' => 5 }
hash.keys #=> ['farbe', 'nummer']
# Hashes can be quickly looked up by key.
hash['Farbe'] #=> "grün"
hash['Nummer'] #=> 5
# Abfragen eines nicht vorhandenen Schlüssels, gibt nil zurück.
hash['nicht vorhanden'] #=> nil
# Wenn du Symbole als Schlüssel in einem Hash verwendest, kannst du
# eine alternative Syntax verwenden.
hash = { :defcon => 3, :action => true }
hash.keys #=> [:defcon, :action]
hash = { defcon: 3, action: true }
hash.keys #=> [:defcon, :action]
# Testen ob ein Schlüssel oder Wert im Hash existiert
hash.key?(:defcon) #=> true
hash.value?(3) #=> true
# Tipp: Arrays und Hashes sind Enumerables!
# Sie haben viele nützliche Methoden gemein, wie each, map, count, und andere.
# Kontrollstrukturen
# Bedingungen
if true
'wenn Bedingung'
elsif false
'sonst wenn, optional'
else
'sonst, auch optional'
end
# Wenn eine Kontrollstruktur keinen Code-Block, sondern einen einzigen
# Ausdruck ausführt, dann kannst du die nachgestellte if-Notation verwenden
warnings = ['Nachname fehlt', 'Adresse zu kurz']
puts("Vorhandene Warnungen:\n" + warnings.join("\n")) if !warnings.empty?
# Formuliere die Bedingung um, wenn sich `unless` besser liest als `if`
puts("Vorhandene Warnungen:\n" + warnings.join("\n")) unless warnings.empty?
# Schleifen
# Traditionell ist das Benutzen von `for` Schleifen in Ruby eher unüblich.
# Stattdessen werden diese mit Hilfe von Enumerables implementiert, was mit
# dem Aufrufen von `each` einhergeht.
(1..5).each do |counter|
puts "Iteration #{counter}"
end
# Was in etwa das selbe ist wie Folgendes (selten in Ruby zu sehen).
for counter in 1..5
puts "Iteration #{counter}"
end
# Das `do |variable| ... end` Konstrukt wird `block` genannt.
# Blocks sind vergleichbar mit Lambdas, anonymen Funktionen
# oder Closures in anderen Programmiersprachen.
# Sie können als Objekte übergeben, aufgerufen oder als Methoden
# zugewiesen werden.
# Die `each` Methode eines Ranges führt den Block einmal für jedes
# Element des Ranges aus.
# Dem Block wird eine counter Variable als Parameter übergeben.
# Du kannst einen Block auch mit geschweiften Klammern schreiben.
(1..5).each { |counter| puts "Iteration #{counter}" }
# Each kann auch über den Inhalt von Datenstrukturen iterieren.
array.each do |element|
puts "#{element} is Teil des Arrays"
end
hash.each do |key, value|
puts "#{key} ist #{value}"
end
# Um auf den Laufindex zuzugreifen kannst du `each_with_index` verwenden
# und eine index Variable definieren.
array.each_with_index do |element, index|
puts "#{element} ist Nummer #{index} im Array"
end
counter = 1
while counter <= 5 do
puts "Iteration #{counter}"
counter += 1
end
#=> Iteration 1
#=> Iteration 2
#=> Iteration 3
#=> Iteration 4
#=> Iteration 5
# Es gibt einige andere hilfreiche Schleifenfunktionen in Ruby.
# Wie etwa 'map', 'reduce', 'inject' und viele andere mehr.
# Map zum Beispiel iteriert über das Array, führt für jedes Element
# die Anweisungen aus,
# die im Block definiert sind und gibt ein völlig neues Array zurück.
array = [1,2,3,4,5]
doubled = array.map do |element|
element * 2
end
puts doubled
#=> [2,4,6,8,10]
puts array
#=> [1,2,3,4,5]
# Case Konstruct
grade = 'B'
case grade
when 'A'
puts 'So wird’s gemacht'
when 'B'
puts 'Viel Glück beim nächsten Mal'
when 'C'
puts 'Das kannst du besser'
when 'D'
puts 'Gerade so durch'
when 'F'
puts 'Durchgefallen!'
else
puts 'Anderes Bewertungssystem, was?'
end
#=> "Viel Glück beim nächsten Mal"
# Case kann auch Ranges benutzen
grade = 82
case grade
when 90..100
puts 'Hurra!'
when 80...90
puts 'OK gemacht'
else
puts 'Durchgefallen!'
end
#=> "OK gemacht"
# Fehlerbehandlung
begin
# Code der einen Fehler wirft...
raise NoMemoryError, 'Dein Speicher ist voll.'
rescue NoMemoryError => exception_variable
puts 'NoMemoryError ist aufgetreten', exception_variable
rescue RuntimeError => other_exception_variable
puts 'RuntimeError ist aufgetreten'
else
puts 'Das wird ausgeführt, wenn keine Fehler geworfen wurden'
ensure
puts 'Dieser Code wird immer ausgeführt, egal was vorher passiert'
end
# Methoden
def double(x)
x * 2
end
# Methoden (und Blocks) geben implizit den Wert des letzten Anweisung zurück.
double(2) #=> 4
# Klammern sind optional wenn die Anweisung dadurch nicht mehrdeutig wird.
double 3 #=> 6
double double 3 #=> 12
def sum(x, y)
x + y
end
# Die Argumente einer Methode werden durch ein Komma getrennt.
sum 3, 4 #=> 7
sum sum(3, 4), 5 #=> 12
# yield
# Alle Methoden haben implizit einen optionalen block Parameter.
# Dieser kann durch das Schlüsselwort 'yield' ausgeführt werden.
def surround
puts '{'
yield
puts '}'
end
surround { puts 'hallo Welt' }
#=> {
#=> hallo Welt
#=> }
# Blocks können in ein 'Proc' Objekt umgewandelt werden.
# Dieses ist eine Art Container um den Block und erlaubt ihn an eine
# andere Methode zu übergeben, ihn in einen anderen Gültigkeitsbereich
# einzubinden oder ihn andersweitig zu verändern.
# Am häufigsten findet man dies bei Parameterlisten von Methoden, in Form
# eines letzten '&block' Parameters, der den Block – wenn es einen gibt –
# entgegen nimmt und ihn in ein 'Proc' umwandelt. Die Benennung '&block' ist
# hier nur eine Konvention; es würde genauso mit '&pineapple' funktionieren.
def guests(&block)
block.class #=> Proc
block.call(4)
end
# Die 'call' Methode eines Proc ist ganz ähnlich zum Aufruf von 'yield', wenn
# ein Block vorhanden ist. Die Argumente, die 'call' übergeben werden, werden
# als Argumente and den Block weitergereicht.
guests { |n| "Du hast #{n} Gäste." }
# => "Du hast 4 Gäste."
# Du kannst eine Liste von Argumenten übergeben, die dann in ein Array
# umgewandelt werden. Dafür gibt es den splat-Operator (`*`).
def guests(*array)
array.each { |guest| puts guest }
end
# Destrukturierung
# Ruby destrukturiert Arrays automatisch beim Zuweisen mehrerer Variablen.
a, b, c = [1, 2, 3]
a #=> 1
b #=> 2
c #=> 3
# In manchen Fällen will man den splat-Operator (`*`) verwenden um ein Array in
# eine Liste zu destrukturieren.
ranked_competitors = ["John", "Sally", "Dingus", "Moe", "Marcy"]
def best(first, second, third)
puts "Gewinner sind #{first}, #{second} und #{third}."
end
best *ranked_competitors.first(3) #=> Gewinner sind John, Sally and Dingus.
# Der splat-Operator kann auch in Parametern verwendet werden.
def best(first, second, third, *others)
puts "Gewinner sind #{first}, #{second} und #{third}."
puts "Es gab #{others.count} andere Teilnehmer."
end
best *ranked_competitors
#=> Gewinner sind John, Sally und Dingus.
#=> Es gab 2 andere Teilnehmer.
# Per Konvention enden alle Methoden, die einen Wahrheitswert zurück geben, mit einem
# Fragezeichen.
5.even? #=> false
5.odd? #=> true
# Wenn ein Methodenname mit einem Ausrufezeichen endet, dann tut diese Methode
# per Konvention etwas Destruktives, wie z.B. das aufrufende Objekt zu
# verändern.
# Viele Methoden haben eine !-Version um eine direkte Änderung zu machen und
# eine Nicht-!-Version, die ein neues Objekt mit den Veränderungen zurück gibt.
company_name = "Dunder Mifflin"
company_name.upcase #=> "DUNDER MIFFLIN"
company_name #=> "Dunder Mifflin"
# Diesmal verändern wir company_name direkt.
company_name.upcase! #=> "DUNDER MIFFLIN"
company_name #=> "DUNDER MIFFLIN"
# Klassen
# Du kannst eine Klasse mit dem Schlüsselwort 'class' definieren.
class Human
# Eine Klassenvariable. Sie wird von allen Instanzen einer Klasse geteilt.
@@species = 'H. sapiens'
# Konstruktor bzw. Initializer
def initialize(name, age = 0)
# Weise das Argument der Instanzvariable 'name' zu.
@name = name
# Wenn kein 'age' angegeben wurde wird der Standartwert aus der Argumentenlist verwendet.
@age = age
end
# Setter Methode
def name=(name)
@name = name
end
# Getter Methode
def name
@name
end
# Getter & Setter können auch kürzer mit der attr_accessor Methode erstellt werden.
attr_accessor :name
# Getter & Setter Methoden können auch einzeln erstellt werden.
attr_reader :name
attr_writer :name
# Eine Klassenmethode unterscheidet sich durch ein 'self' von einer
# Instanzmethode.
# Sie kann nur auf der Klasse und nicht auf einer Instanz der Klasse
# aufgerufen werden.
def self.say(msg)
puts msg
end
def species
@@species
end
end
# Instanziieren einer Klasse
jim = Human.new('Jim Halpert')
dwight = Human.new('Dwight K. Schrute')
# Du kannst die Methoden des erstellten Objekts aufrufen.
jim.species #=> "H. sapiens"
jim.name #=> "Jim Halpert"
jim.name = "Jim Halpert II" #=> "Jim Halpert II"
jim.name #=> "Jim Halpert II"
dwight.species #=> "H. sapiens"
dwight.name #=> "Dwight K. Schrute"
# Aufrufen einer Klassenmethode
Human.say('Hi') #=> "Hi"
# Der Gültigkeitsbereich einer Variablen wird durch ihren Namen definiert.
# Variablen, die mit $ beginnen sind global gültig.
$var = "Ich bin eine globale Variable"
defined? $var #=> "global-variable"
# Variablen, die mit @ beginnen, sind innerhalb einer Instanz gültig.
@var = "Ich bin eine Instanzvariable"
defined? @var #=> "instance-variable"
# Variablen, die mit @@ beginnen, sind für die Klasse gültig.
@@var = "Ich bin eine Klassenvariable"
defined? @@var #=> "class variable"
# Variablen, die mit einem Großbuchstaben beginnen, sind Konstanten
Var = "Ich bin eine Konstante"
defined? Var #=> "constant"
# Class ist in Ruby auch ein Objekt. Deshalb kann eine Klasse Instanzvariablen
# haben. Eine Klassenvariable wird zwischen der Klasse und all ihren
# Ableitungen geteilt.
# Basis Klasse
class Human
@@foo = 0
def self.foo
@@foo
end
def self.foo=(value)
@@foo = value
end
end
# Abgeleitete Klasse
class Worker < Human
end
Human.foo #=> 0
Worker.foo #=> 0
Human.foo = 2
Worker.foo #=> 2
# Ableitungen einer Klasse haben keinen Zugriff auf eine Eine Klassen-Instanzvariable.
class Human
@bar = 0
def self.bar
@bar
end
def self.bar=(value)
@bar = value
end
end
class Doctor < Human
end
Human.bar #=> 0
Doctor.bar #=> nil
module ModuleExample
def foo
'foo'
end
end
# Ein Einbinden (include) eines Moduls bindet seine Methoden an die Instanzen
# der Klasse.
# Ein Erweitern (extend) eines Moduls bindet seine Methoden an die Klasse
# selbst.
class Person
include ModuleExample
end
class Book
extend ModuleExample
end
Person.foo #=> NoMethodError: undefined method `foo' for Person:Class
Person.new.foo #=> "foo"
Book.foo #=> "foo"
Book.new.foo #=> NoMethodError: undefined method `foo'
# Callbacks werden ausgeführt, wenn ein Modul eingebunden oder erweitert wird.
module ConcernExample
def self.included(base)
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
end
module ClassMethods
def bar
'bar'
end
end
module InstanceMethods
def qux
'qux'
end
end
end
class Something
include ConcernExample
end
Something.bar #=> "bar"
Something.qux #=> NoMethodError: undefined method `qux'
Something.new.bar #=> NoMethodError: undefined method `bar'
Something.new.qux #=> "qux"
(z.T. auf Englisch)
Du hast einen Verbesserungsvorschlag oder einen Fehler gefunden? Erstelle ein Ticket im offiziellen GitHub Repo, oder du erstellst einfach gleich einen pull request!
Originalversion von David Underwood, mit Updates von 20 contributor(s).