
Ruby ist eine plattformunabhängige, interpretierte, dynamisch typisierte, inhärent objektorientierte Programmiersprache, die auch prozedural, funktional und aspektorientiert eingesetzt werden kann. Ruby ist Anfang der 1990er Jahre vom Japaner Yukihiro „Matz“ Matsumoto entwickelt worden. Der Name Ruby ist eine Anspielung auf die Sprache Perl.
Alleinstellungsmerkmale
Mit Ruby wollte Matsumoto eine Sprache schaffen, die eine gute Balance aus imperativer und funktionaler Programmierung schafft und dabei die besten Features seiner Lieblingssprachen Perl, Smalltalk, Eiffel, Ada und Lisp mit einfließen lässt. Ein zentrales Ziel von Ruby laut Matsumoto ist es dem Programmierer Freude zu bereiten.
For me, the purpose of life is, at least partly, to have joy. Programmers often feel joy when they can concentrate on the creative side of programming, so Ruby is designed to make programmers happy.
Yukihiro “Matz” Matsumoto
Einsatzbereiche
Ruby hat mit dem vom Dänen David Heinemeier Hansson 2004 erstmalig veröffentlichten Full-Stack-Webframework Ruby on Rails einen erheblichen Popularitätsschub erhalten. Schaut man sich Stellenanzeigen für Ruby-Entwickler an, so taucht eigentlich auch immer das Stichwort Rails in der Beschreibung mit auf.
Darüber hinaus sind einige systemnahe Tools in Ruby geschrieben, darunter Homebrew, Chef, Puppet, YaST, Vagrant und Metasploit. Auch GitLab und Travis CI sind zum Teil in Ruby geschrieben. Heroku ist ursprünglich als reine Ruby-Plattform gestartet.
Pros
Ruby ist sehr darauf bedacht, eine für den Entwickler angenehme Sprache zu sein. Sowohl das Lesen als auch das Schreiben von Code gehen leicht von der Hand. Ruby ist näher an der menschlichen Sprache und Denkweise als viele andere Programmiersprachen, wie folgender Code verdeutlicht:
name = readline
print "your name is #{name}" unless name.empty?
Ruby löst das Problem schlecht lesbarer negierter Bedingungen durch zusätzliche Schlüsselwörter, die if und while ergänzen. Statt if not schreibt man unless
, statt while not schreibt man until
.
Ein Aspekt von Rubys Flexibilität ist es, dass beliebige Klassen zur Laufzeit erweitert oder Bestandteile überschrieben werden können. Letzteres wird auch als Monkeypatching bezeichnet und kann z.B. dazu genutzt werden, bekannte Fehler in einer Bibliothek, die man verwendet, selbst zu fixen, ohne die Bibliothek dafür anfassen zu müssen.
Der folgende Code überschreibt die Plus-Methode der Klasse Integer
, was dazu führt, dass die Operation 5+3
den Wert 2
zurückgibt:
class Integer
def +(obj)
return self-obj
end
end
puts 5+3 # gibt 2 zurück, da 5-3=2
Ruby unterstützt nativ Arrays (Listen) :
[1, "Hallo Welt", true].each do |key| puts key end
# Ausgabe:
# 1
# Hallo Welt
# true
Ebenso Hashes (assoziative Arrays) :
{ "rot" => 0xff0000, "gruen" => 0x00ff00, "blau" => 0x0000ff}.each do |key, value| print key, " => ", value, "\n" end
# Ausgabe:
# rot => 16711680
# gruen => 65280
# blau => 255
Und Ranges:
(1...10).each { |number| print number, "," }
('A'..'Z').each { |letter| print letter }
# Ausgabe:
# 1,2,3,4,5,6,7,8,9ABCDEFGHIJKLMNOPQRSTUVWXYZ
Drei Punkte bedeuten dabei, dass der letzte Wert exklusiv ist, bei zwei Punkte ist er inklusiv. Wie das Beispiel zeigt funktionieren Ranges auch über Strings.
Blocks sind ein weiteres interessantes Konstrukt der Sprache Ruby. Über einen Block lässt sich u.a. eine Folge von Instruktionen an eine Methode übergeben, was sich übrigens auch die in den obigen Beispielen demonstrierte Methode each
zunutze macht: Sie nimmt als Argument einen parametrisierten Block entgegen, wobei der/die Block-Parameter die Werte zwischen den |
Pipes|
darstellen und die darauffolgenden Anweisungen den eigentlichen Block repräsentieren.
Aufgrund seiner Syntax ist Ruby eine beliebte Sprache zum Schreiben domänenspezifischer Sprachen (DSLs). Dadurch, dass bei Methodenaufrufen die runden Klammern ausgelassen werden können und Anweisungen nicht mit einem Semikolon beendet werden müssen, kann Ruby-Code als DSL eher wie eine Auszeichnungssprache, als wie eine Programmiersprache wirken.
Ruby bietet auch Möglichkeiten zur Metaprogrammierung. So können zur Laufzeit Methoden generiert, die Vererbungshierarchie manipuliert oder Instanzvariablen geändert werden. Das folgende Beispiel erzeugt für die Klasse Integer
neue Methoden aus einer Liste, die die Zeichenkette „Hallo <Methodenname> <Integer-Wert>“ ausgeben:
class Integer
def magic(items)
items.each do |item|
self.class.send(:define_method, "#{item}") { puts "hallo #{item} #{self.to_s}" }
end
end
end
liste = ["eins", "zwei", "drei"]
0.magic(liste)
1.eins
2.zwei
3.drei
# Ausgabe:
# hallo eins 1
# hallo zwei 2
# hallo drei 3
Cons
Ruby kann durch Monkeypatching und Metaprogrammierung, sowie den vielfältigen Möglichkeiten, ein bestimtes Ziel auf verschiedene Arten und Weisen zu erreichen, schnell undurchsichtig werden. Erschwerend kommt hinzu, dass sich im Laufe der Zeit verschiedene Programmierstile entwickelt haben. Da Ruby keine Deklaration von Variablen erfordert, können auch Tippfehler zu schwer nachvollziehbaren Problemen führen, wenn man den Code nicht ausreichend durch Tests abgesichert hat.
Unveränderlichkeit (Immutability) ist eine wichtige Eigenschaft, wenn es darum geht Code robuster und vor allem threadsicher zu gestalten. Ruby bietet hier zwar mehrere Möglichkeiten, z.B. die Methode freeze, nach deren Aufruf eine Variable nicht mehr geändert werden kann, jedoch ist dies umständlicher als in anderen Sprachen, die eine Variable oftmals durch die Ergänzung eines Schlüsselworts als Konstante markieren können.
Auch wenn Ruby-Entwickler meinem persönlichen Eindruck nach sehr für die Sprache schwärmen, hat Ruby in letzter Zeit an Popularität verloren, was aus meiner Sicht vor allem an der starken Konkurrenz liegt. Sprachen wie Python, PHP und Perl, mit denen Ruby gerne verglichen wird, sind nämlich ebenso breit vertreten. Da hat es eine Sprache wie Java leichter, die sich durch ihre Eigenschaften besser von anderen Sprachen differnzieren kann.
Datenblatt
Name | Ruby |
Webseite | https://www.ruby-lang.org |
Erscheinungsjahr | 1995 |
Aktuellste Version (Stand 20. Dezember 2020) | Version 2.7.1 vom 31. März 2020 |
Typisierung | dynamisch |
Paradigmen | imperativ prozedural objektorientiert funktional aspektorientiert |
Pros | Cons |
---|---|
angenehm zu lesen | langsamer als kompilierbare Sprachen |
schlanke, einfache Syntax | hat in den letzten Jahren an Popularität verloren |
extrem flexibel | Flexibilität kann sich nachteilig auf die Lesbarkeit auswirken |
umfangreiche Standardbibliothek | Immutability umständlich bzw. schwer zu realisieren |
viele native Datentypen (z.B. Arrays, Hashes, Regex, Ranges, Symbols, rationale/komplexe Zahlen) | |
gute geeignet für domänenspezifische Sprachen | |
vielseitige Möglichkeiten zur Metaprogrammierung | |
plattformunabhängig | |
interaktive Shell (REPL) |
virtuallet
virtuallet ist ein kleines Programm von mir, welches ich in diversen Programmiersprachen implementiert habe. Hier geht es direkt zum Ruby-Code von virtuallet auf GitLab. Hier gibt es weitere Infos zu virtuallet.