Ruby

Lesezeit: 7 Minuten

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

NameRuby
Webseitehttps://www.ruby-lang.org
Erscheinungsjahr1995
Aktuellste Version (Stand 20. Dezember 2020)Version 2.7.1 vom 31. März 2020
Typisierungdynamisch
Paradigmenimperativ
prozedural
objektorientiert
funktional
aspektorientiert
ProsCons
angenehm zu lesenlangsamer als kompilierbare Sprachen
schlanke, einfache Syntaxhat in den letzten Jahren an Popularität verloren
extrem flexibelFlexibilität kann sich nachteilig auf die Lesbarkeit auswirken
umfangreiche StandardbibliothekImmutability 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.