Willkommen auf Pelzkuh.de
Hier finden sich Neuigkeiten rund um interessante Themen aus der (Computer-)Technik und den Pelzkuh.de Development Server. Zugriff gibt es über die Trac Links.

Ruby - schräg oder cool?

In der Reihe Weiterbildung IT ("Oberseminar Programmiersprachen"), die wir zuletzt etwas schleifen haben lassen, kümmere ich mich heute für alle Interessierten sozusagen im Fernstudium um eine kurze Übersicht über die Features von Ruby, die Klaus diese Woche kurz vorgestellt hat. Soweit hat mich Informatik mittlerweile doch beeinflusst - ich werde keine Befehlsübersicht geben, sondern versuchen, die Konstrukte übergeordneten Konzepten zuzuordnen.

Außerdem: Es wird mal wieder Zeit für einen Post auf Pelzkuh, nachdem Andreas und ich zwar doch schon einiges an Posts gesammelt haben, unser Interlocking (Autorenwechsel pro Post-Anzahl) mit 3/15 aber immer noch hundmiserabel ist...

Zum Ausprobieren installiert ist Ruby schnell - unter allen Debianartigen (Ubuntu, Mint, ...) reicht ein

apt-get install irb

und schon hat man eine interaktive Konsole, in die man nach Belieben Shellscripts einbinden kann. Natürlich kann man auch klassisch deployment-orientiert entwickeln.

So, wo fangen wir an? Am besten mit den drei Kern eigenschaften: objektorientiert (radikal konsequent, mehr noch als Java), dynamisch, aber stark typisiert. Am Beispiel:

#dynamisch typisiert
a = 5
=> 5
#stark typisiert
5 + "5"
TypeError: String can't be coerced into Fixnum
#streng objektorientiert
5.class
=> Fixnum

Was man gleich sieht: die Syntax kommt sehr reduziert daher - Befehlsendmarker fehlen und bei einer leeren Argumentliste dürfen die Klammern weggelassen werden.
Schauen wir uns ein paar Spielereien mit String an:

#Praktischer Zugriff auf Variablen für Ausgaben
a = 5
c = "Es regnet schon seit #{a} Tagen!"
 => "Es regnet schon seit 5 Tagen!"
#Reguläre Ausdrücke
t = Time.now.to_s
=> "Sat Jul 14 12:06:48 +0200 2012"
#Alternativ gibt es auch die match-Methode. Tildenoperator liefert den Index im String, wo's passt
t =~ /(..):(..):(..)/
=> 11
#Wie in vielen Shells gibt es mit $ dann die geklammerten Teilausdrücke
$1
=> "12"

Lassen wir die Spielereien. Ein Blick auf die Datenstrukturen. Hier gibt es Array, Hash und Range:

 #Array
 a = [1,2,5,8]
=> [1, 2, 5, 8]
a[2]
=> 5
#Hash
b = {"a" => 1, "b" => 5}
=> {"b"=>5, "a"=>1}
b["a"]
=> 1
#Add Element
b["c"] = 7
=> 7
b
=> {"c"=>7, "b"=>5, "a"=>1}
#Range
(0..8)
=> 0..8


Jetzt wird's lustig: jetzt kommen die Schleifen über den Strukturen - da weiß ich immer nicht, ob ich lachen oder weinen soll...

(0..8).collect{|num| num+num}.select{|num| if (num > 10) then num end}.each{|num| puts num}
12
14
16
=> [12, 14, 16]


Wer ist mitgekommen? Also schön, noch mal ausführlich:

#einfache each-Schleife
(0..8).each{|num| puts num}
0
1
2
3
4
5
6
7
8
=> 0..8
#collect sammelt die Ergebnisse gleich wieder in einem neuen Array auf:
(0..8).collect{|num| num+num}
=> [0, 2, 4, 6, 8, 10, 12, 14, 16]
#select wählt nur bestimmte Einträge aus
(0..8).select{|num| if(num > 5) then num end}
=> [6, 7, 8]

Wem ich verrate, wie man Dateien in Ruby öffnen kann, der merkt, wie mächtig schon nur mit regulären Ausdrücken und den drei Schleifen simple Einzeiler sein können...

file = File.open("beispiel.txt")
contents = file.read

So, noch ein paar Sätze zur Erstellung von eigenen Klassen. Zeigen wir einfach mal alles wesentliche an einem Beispiel:

class Person
    #bestellt den getter und setter frei Haus!
    attr_accessor :vorname, :nachname
    def initialize(vorname, nachname)
        @vorname = vorname
        @nachname = nachname
    end
    #was lernen wir? Das letzte Statement ist immer der Rückgabewert!
    def to_s
        "Der Mensch heißt #{vorname} #{nachname}."
    end
end

Und schon geht's los:

p = Person.new("Max", "Muster")
puts p
    Der Mensch heißt Max Muster.
p.vorname = "Maximilian"
=> "Maximilian"
puts p
    Der Mensch heißt Maximilian Muster.

Wie sagt der Schwabe: ich bin begeischtert! Das soll für heute reichen - nur noch ein paar Informationen im Überblick

  • Anstelle von einzigartigen Variablen (bei Java gern als static int irgendwas) kann ich gleich mit vorangestelltem Doppelpunkt Symbole mit Objektidentität erzeugen (z.B. :erdradius)
  • Methoden, die ein Boolean liefern (is..., has...) enden gerne auf "?", Methoden, die einen Seiteneffekt haben, gerne auf "!"
  • Es gibt zwar keine Mehrfachvererbung, aber Mix-Ins. Überall darf also einfach Code dabei stehen, der dann entweder eingebunden oder gleich ausgeführt wird.
  • Wer Objekte sortieren will, bucht einfach den Comparator zu und definiert die Vergleichsmethode:
include Comparable
attr :str
def <=>(anOther)
    str.size <=> anOther.str.size
end

Kommentare:

  1. Ui ui ui... die Schleifen sind ja echt abenteuerlich... aber irgendwie faszinierend. Danke! sehr aufschlußreich.

    AntwortenLöschen
  2. Übrigens noch ein paar Ergänzungen/Anregungen vom Ruby-Experten, die mir Klaus heute zugeschickt hat:

    1)
    (0..8).collect{|num| num+num}.select{|num| if (num > 10) then num
    end}.each{|num| puts num}

    # Viel zu kompliziert:

    (0..8).collect{|num| num+num}.select{|num| num > 10 }.each{|num| puts num}

    # und eigentlich natürlich:

    (0..8).select { |n| n>5 }.each { |n| puts n }

    2)

    file = File.open("beispiel.txt")
    contents = file.read

    # Besser, um ein automatisches file.close zu haben:
    # das Verlassen des Blocks schließt die Datei.

    contents = File.open("beispiel.txt") { |file| file.read }

    # und noch besser

    contents = File.read("beispiel.txt")

    AntwortenLöschen