Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 1 Inhaltsverzeichnis Was ist Ruby? ............................................................................................................................................... 2 Implementierungen .................................................................................................................................. 2 Einsatzbereiche ........................................................................................................................................ 2 Quellen ......................................................................................................................................................... 3 Einige Speziellere Themen.................................................................................................................... 4 Erste Schritte ................................................................................................................................................ 5 Ruby Installation ....................................................................................................................................... 5 Ruby Objekttypen ..................................................................................................................................... 5 Variablen .............................................................................................................................................. 5 Ganzahlwerte (Integers) ....................................................................................................................... 5 Fließkommawerte (Float) ..................................................................................................................... 6 Zeichenketten (Strings) ........................................................................................................................ 6 Arrays.................................................................................................................................................... 7 Hashes (Dictionaries) ............................................................................................................................ 8 Symbole ................................................................................................................................................ 8 Wahrheitswerte (Booleans) ................................................................................................................. 8 Folgen (Ranges) .................................................................................................................................... 8 Konstanten ........................................................................................................................................... 9 Kontrollstrukturen .................................................................................................................................... 9 Verzweigungen (If, else elsif)................................................................................................................ 9 Schleifen (loop do, while, until) .......................................................................................................... 10 Iteratoren ........................................................................................................................................... 10 Code-Blocks ............................................................................................................................................ 10 Was sind Code-Blocks? ....................................................................................................................... 10 Suchen mit Hilfe von Code-Blocks ...................................................................................................... 11 Hashes verbinden mit Hilfe von Code-Blocks..................................................................................... 11 Ranges, Arrays und Hashes mit Hilfe von Code-Blocks verarbeiten .................................................. 11 Sortieren mit Hilfe von Code-Blocks................................................................................................... 12 Werte akkumulieren mit Hilfe von Code-Blocks ................................................................................ 12 Methoden ............................................................................................................................................... 12 Definition uns Aufruf von Methoden ................................................................................................. 12 Definition von Argumenten für Methoden ........................................................................................ 12 Codebeispiele ............................................................................................................................................. 21 Primzahlensieb: .................................................................................................................................. 21 Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 2 Was ist Ruby? Zitat aus „Programmierung in Ruby, Der Leitfaden der Pragmatischen Programmierer“, Dave Thomas: „Nimm eine richtig objekt-orientierte Sprache, etwa Smalltalk. Schmeiß die ungewöhnliche Syntax raus und benutze einen etwas konventionelleren, datei-basierten Quell-Code. Nun füge ein gutes Maß an Flexibilität und Komfort solcher Sprachen wie Python oder Perl hinzu. Das alles zusammen ergibt Ruby.“ Ruby (englisch für Rubin) ist eine höhere Programmiersprache, die Mitte der neunziger Jahre von dem Japaner Yukihiro Matsumoto entworfen wurde. Ruby ist interpretiert und objektorientiert, unterstützt aber mehrere weitere Programmierparadigmen (unter anderem prozedurale und funktionale Programmierung sowie Nebenläufigkeit), bietet dynamische Typisierung, Reflexion und automatische Speicherbereinigung (Garbage Collection – allerdings laut Berichten eher ineffizient). Ruby ist wie Smalltalk vollständig objektorientiert: Alle Datentypen sind in Ruby Objekte, auch solche, die in vielen anderen Sprachen als primitive Datentypen gelten, wie etwa Zahlen oder Zeichen. Ruby unterstützt mehrere Ansätze der Vererbung (allerdings nicht Mehrfachvererbung). Implementierungen Die Referenzimplementierung von Ruby (aktuelle Version: 1.9.3) wurde von Yukihiro „Matz“ Matsumoto als Interpreter in C entworfen und wird meist als MRI (Matz's Ruby Interpreter) oder auch als CRuby oder MatzRuby bezeichnet und ist derzeit am weitesten verbreitet. Den Kern bildet YARV (Yet Another Ruby VM), eine virtuelle Maschine. Statt ein Rubyprogramm direkt auszuführen, wird es zunächst in Bytecode übersetzt und dann von YARV interpretiert, wodurch sich ein Geschwindigkeitsvorteil ergibt. Der offizielle Interpreter ist als offener Quellcode (C) verfügbar und daher auf jedem System kompilierbar. Installer (die das Leben deutlich leichter machen) gibt es für Linux, Windows und OS X sowie einige exotischere Systeme. Es gibt aber z.B. auch Implementierungen von Ruby in Java (JRuby eine Neuimplementierung des Ruby-Interpreters in Java mit dem Ziel, Ruby nahtlos in die Java-Plattform zu integrieren.) speziell angepasst an bestimmte Systeme/Libraries (z.B. IronRuby - eine Implementierung, die Ruby ins .NET-Framework integriert und in C# implementiert ist. MacRuby - eine Implementierung in Objective-C von Apple) und andere. Einsatzbereiche Für folgende Einsatzbereiche ist Ruby (wie auch Perl, Python und PHP) beliebt: Werkzeuge Systemadministration webbasierte Anwendungen, Webentwicklung Prototypen Wegwerfskripte Kommandozeilen-orientiert und GUIorientiert Netzwerk-Tools Datenbankunterstützung für alle gängigen SQL-Datenbanken vorhanden Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 3 Dafür sorgen unter anderem folgende Features: Textmanipulation Administration regexp, Parser, Lexer, Formatierung, Konverter syslog tar, zlib Encryption Multithreading Server/Daemons XML Netzwerk Mail: smtp, pop3, IMAP, Mailmanipulation, Mailgenerierung Internet: http, ftp, ssl, eigenständiger Webserver (webrick), XML Shell: telnet, ssh Webentwicklung: mehrere WebFrameworks (Ruby On Rails, Wee, Amrita, Nitro), Bildbearbeitung mit ImageMagick Client/Server Programming: Distributed Ruby (dRuby) Socket-Programmierung: tcpsocket, udpsocket ... GUI Fox GUI Ruby TK Windows Zugriff auf Windows API, DLL-Zugriff, OLE-Zugriff Registry-Manipulation Persistenz/Serialisierungssprachen Datenbank Zugriff auf alle gängigen SQLDatenbanken einheitliches Interface, Kapselung der darunterliegenden Datenbank objektorientierte Datenbankadapter (z.B. Nitro/ Og) PStore - Objekte auf Festplatte ablegen YAML - Serialisierungssprache, auch ideal für Configdateien Quellen Die Heimatseite von Ruby http://www.ruby-lang.org/de/ Hier bekommt man die aktuelle Ruby Version (dzt. 1.9.3) http://www.ruby-lang.org/de/downloads/ Nettes Online-Tutorial (Installation von Ruby nicht nötig) http://tryruby.org Weitere interessante Links mit Tutorials (auch Videos) und Beispielen: http://www.approximity.com/rubybuch2/ http://www.rubyist.net/~slagell/ruby/misc.html http://showmedo.com/videotutorials/series?name=fXRfVLC1J http://www.wikidorf.de/reintechnisch/Inhalt/EinladungInRuby http://hinterkattentuffel.de/ruby/tutorial.htm http://www.ruby-doc.org/docs/Einfuhrung_in_Ruby/ http://www.zenspider.com/Languages/Ruby/QuickRef.html Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 4 Ein gutes Einsteigerbuch auf Deutsch und frei verfügbar „Programmierung in Ruby. Der Leitfaden der Pragmatischen Programmierer“ http://home.vrweb.de/~juergen.katins/ruby/buch/index.html Und natürlich die offizielle Ruby Dokumentation http://www.ruby-doc.org/core-1.9.3/ http://www.ruby-doc.org/stdlib-1.9.3/ Die Ruby Wiki (auf Deutsch) http://wiki.ruby-portal.de/Hauptseite Auch SelfRuby darf nicht fehlen (wenn auch bei weitem nicht so ausführlich wie SelfHTML) http://www.joelh.de/selfruby/index.php Einige Speziellere Themen Reguläre Ausdrücke in Ruby (deutsch) http://www.wikidorf.de/reintechnisch/Inhalt/RubyRegExpTutorial http://www.wikidorf.de/reintechnisch/Inhalt/RubyRegexp GUI Toolkits für Ruby, für jene die gern Fensterln http://home.arcor.de/scite/ Anleitung wie man aus Ruby Programmen ausführbare Windows-Programme generiert http://ocra.rubyforge.org/ Doku und Links zu wichtigen (und weniger wichtigen) Ruby Libraries (wie z.B. Rails (Web Application Framework) und Yard (Ruby Dokumentation Framework)) http://www.rubydoc.info/ Und für den Fall dass man in der Linux Shell programmieren will/muss hier eine Kurzübersicht zu BASH http://www.wikidorf.de/reintechnisch/Inhalt/ShellKurzueberblick ANMERKUNG: In den eingefügten Codeabschnitten sind die angezeigten Anführungszeichen im Text immer als identisch zu betrachten auch wenn sie am Ausdruck unterschiedlich aussehen. Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 5 Erste Schritte Ruby Installation Am besten (unter Windows) mit dem Installer unter http://rubyinstaller.org/ -> Download -> Version auswählen (derzeit ist 1.9.3 die aktuellste). Runterladen, Ausführen, Lizenzbedingungen bestätigen und dann alle Optionen die man möchte ankreuzen und installieren. Damit ist der Ruby Interpreter, die Interaktive Ruby Shell (irb) und einige Doku installiert. Für andere Systeme (Linux, OS X) finden sich unter http://www.ruby-lang.org/de/downloads/ Anleitungen für die Installation. Als Entwicklungsumgebungen bieten sich Netbeans (nur bis Version 6.9.1 unterstützt), Eclipse (Aptana Studio 3 installieren für Ruby Support) oder Notepad++ (für die die es etwas weniger voluminös mögen) an. Ruby Objekttypen Variablen Variablen sind Referenzen auf Objekte und sind entweder undefiniert (nil) oder verhalten sich wie Objekte. Variablenzuweisung: {variablenname} = {Wert} z.B.: x = 1 Variablenkonventionen: Variablen starten mit einem Kleinbuchstaben und benutzen „_“ als Trennzeichen. Zusatzangaben bei Variablen (Sichtbarkeit): Die Sichtbarkeit (Gültigkeit) von Variablen wird in Ruby durch das Voranstellen von „$“ für globale Variablen und „@“ für Instanz- bzw. „@@“ für Klassenvariablen gekennzeichnet. Alle anderen Variablen sind Lokale bzw. Blockvariablen. Ganzahlwerte (Integers) Bignum und Fixnum Integerwerte gehören einer von 2 Subklassen der Klasse Integer an. „Fixnum“ und „Bignum“ die sich nur durch die Art der Speicherung unterscheiden. Dabei kann Bignum wirklich groß werden (probiere 9999 ** 9999). Basisoperationen +, -, *, /, % (Divisionsrest), ** (Potenz), & (Bitweises Und), | (Bitweises Oder), ^ (Bitweises exclusives Oder), >> (Bitshift nach rechts), << (Bitshift nach links) Zuweisungen Wie in anderen Programmiersprachen auch ist die Zuweisung verkürzbar. Z.B. x = x + 2 kann auf x +=2 verkürzt werden. Dies funktioniert aber hier mit jedem (!) Operator. Wichtige Methoden der Integer Klassen .abs (Absolutwert), .even?, .odd? (Test auf gerade bzw. ungerade), [n] (n-tes Bit der Zahl), .to_f (in Float umwandel), .to_s (in String umwandeln), .to_s(basis) (in String umwandeln mit angegebene Basis von 2 bis 36), .size (Speichergröße in Byte, für Bignum interessant). Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 6 Fließkommawerte (Float) Die Float-Klasse Float-Werte werden durch den Dezimalpunkt „.“ gekennzeichnet. Sobald bei einer Operation ein FloatWert verwendet wird, wird auch das Ergebnis als Float-Wert berechnet. Allerdings liegt hier eine gemeine Falle verborgen, da auch das umgekehrte gilt. Wo kein Float-Wert in einer Rechnung enthalten ist, wird auch kein Float-Wert berechnet. So ergibt z.B. 10 / 3 den Integer-Wert 3. Möchte man genau rechnen, so muss man entweder 10 / 3.0 oder 10.0 / 3 oder 10.0 / 3.0 angeben. In allen drei Fällen erhält man den erwarteten Wert 3.3333333333333. Wichtige Methoden der Float-Klasse .round (für kaufmännische Rundung), .floor (für Abrundung), .ceil (für Aufrundung), .to_i (für Abschneiden der Nachkommastellen, auch .to_int oder .truncate) -> alle Methoden liefern einen Integerwert zurück .round(Stellen) (für Kaufmännische Rundung auf die angegebene Stellenanzahl) Außerdem sind alle Operationen und Methoden der Integer-Klassen anwendbar bis auf die bitweisen Operationen (&,|,^,>>,<<, to_s(basis), [n]) sowie even? und odd?. Zeichenketten (Strings) Was sind Strings? Strings sind beliebig lange Zeichenketten in einfachen (‘) oder doppelten (“) Anführungszeichen wobei in der Doppelanführungszeichen-Version einen Auswertung von sogenannten Escape-Zeichen erfolgt. Beachte den Unterschied zwischen puts “\ta\tb\nc\nd“ und puts ‘\ta\tb\nc\nd‘ . In dieser Version ist es auch möglich Variablen auszuwerten die wie folgt gekennzeichnet werden: #{Variablenname} also z.B.: puts “Ihr Name ist #{ihr_name}“ Aber in den geschwungenen Klammern kann man auch Ruby Ausdrücke auswerten. So gibt die Zeile puts “1 + 1 = #{1+1}“ wie erwartet „1 + 1 = 2“ aus. String-Operationen und Methoden + fügt Strings zusammen, * vervielfältigt einen String (also z.B. “A“*5 ergibt “AAAAA“). Strings kann man als Formatierungsanweisung verwenden (str % arg wobei arg ein beliebiges Objekt sein kann das formatiert werden kann (String, Float, Integer,…)). Beispiel: “%05d“ % 123 zeigt “00123“ an. “%-5s: %04x“ % [“ID“, 65535] zeigt “ID : ffff“ an. .reverse (umkehren einer Zeichenkette “Hallo“.reverse -> “ollaH“), .downcase, .upcase (umwandeln in Klein- bzw. Großbuchstaben), .length (Länge des Strings ermitteln), [n] (n(+1)-tes Zeichen des Strings), [n..m] (n(+1)-tes bis m(+1)-tes Zeichen des Strings), [n,m] (m Zeichen vom n(+1)-ten Zeichen des Strings), .lstrip, .rstrip, .strip (Leerzeichen links, rechts bzw. links und rechts entfernen), .to_c (Umwandlung in Komplexe Zahl), .to_i, .to_f, .to_r (Umwandlung in Integer, Float oder Bruch (rational)) In Strings kann mit regulären Ausdrücken gesucht werden siehe http://www.wikidorf.de/reintechnisch/Inhalt/RubyRegExpTutorial und http://www.wikidorf.de/reintechnisch/Inhalt/RubyRegexp Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 7 Arrays Besonderheiten von Arrays in Ruby Ruby-Arrays können jede Art von Objekt enthalten und das auch bei unterschiedlichen Typen. Also Strings, Zahlen, weitere Arrays und gemischte Typen. Arrays werden mit eckigen Klammern gekennzeichnet [ ]. Die Elemente im Array werden durch Komma getrennt “,“. Hat man ein Array deklariert (z.B. my_array = [“a“, “b“, “c“]) dann kann man mit my_array[1] das Element des Arrays an der Position 1 welches in diesem Fall „b“ entspricht ansprechen. Arrays sind also 0-basiert (wie in vielen anderen Programmiersprachen auch). Man kann dem Array direkt auch Werte zuweisen (my_array[1] = “x“ ) oder anhängen (my_array << “y“). Nach diesen Aktionen ist my_array gleich [“a“, “x“, “c“ , “y“] Array-Methoden .inspect liefert eine Repräsentation des Arrays als String mit Delimitern die zur Analyse eines Arrays geeignet sind. .to_s wandelt die Elemente eines Arrays in einen String (ohne Delimiter) um ebenso wie .join jedoch mit dem Unterschied dass man bei Join auch noch ein Trennzeichen (z.B. .join(“,“)) angeben kann. Mit .split(“{Trennzeichen}“) lässt sich ein String auch wieder in ein Array umwandeln. .sort liefert ein sortiertes Array als Ergebnis (funktioniert nur bei einfachen Arrays). .uniq liefert ein Array in dem alle Doublette entfernt wurden als Ergebnis. Mit .sort! bzw. .uniq! wird die Änderung auch ins Array übernommen (also das Array verändert). Das funktioniert sinngemäß bei vielen Ruby Methoden so. .delete_at(n) löscht das (n+1)-te Element aus dem Array und liefert dieses Element als Ergebnis. .delete({Element}) löscht das Element (alle Vorkommnisse) welches als Parameter angegeben ist aus dem Array. .delete_if(|item| block) liefert die Möglichkeit bedingten Löschens (s.u.). << {Element} fügt ebenso wie .push({Element}) ein Element an das Array (hinten) an während .pop das letzte Element entfernt. Ebenso entfernt .shift das erste Element das Arrays und .unshift({Element}) fügt das Element an erster Stelle ein. .push und .unshift liefern als Ergebnis das Array, .pop und .shift das entfernte Element zurück. Man Kann mit Arrays auch „Rechnen“. Mit + lassen sich Elemente hinzufügen mit – entfernen wobei jeweils (wie in Mengenoperationen) beide Operanden Arrays sein müssen, mit * (int) läßt sich ein Array vervielfachen. Und weil wir gerade bei der Mengenlehre sind, mit & lässt sich die Schnittmenge zweier Arrays bilden. Mit [n] bzw. .at(n) kann das (n+1)-te Element angesprochen werden wobei wenn n negativ ist das n-te Element von hinten zurückgeliefert wird. .count liefert die Anzahl der Element wobei die Variante .count({Element}) die Anzahl der Vorkommnisse des Elements und .count(|item| block) die Anzahl der Elemente zurückgeliefert wird, die der Regel im block entsprechen (z.B. liefert bei a=[1,2,4,2] , a.count{|x| x%2==0} das Ergebnis 3 zurück. ………… u.v.m. ………. Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 8 Hashes (Dictionaries) Im Gegensatz zu Arrays sind Hashes unsortierte Objektsammlungen, die über Schlüssel zugegriffen werden. Jeder Hasheintrag besitzt also aus einem Schlüssel und einem Objekt. Hashes werden in geschwungenen Klammern angegeben wobei der Schlüssel und das Objekt durch => getrennt sind. Also z.B. person = {‘vorname‘ => ‘Heinz‘, ‘zuname‘ => ‘Schindelar‘, ‘wohnort‘ => ‘Baden‘ } Mit [{Schlüsselwert}] erhält man das zum Schlüssel gehörige Objekt (z.B. person[‘vorname‘] liefert “Heinz“ ) Sowohl der Schlüsselwert als auch das referenzierte Objekt kann ein beliebiger Objekttyp sein (Integer, Float, String, Array,…) und das auch durchaus gemischt. An Methoden ähneln Hashes Arrays außer dass der Zugriff über den Schlüsselwert statt über die Position erfolgt und dass Hashes nicht sortiert sind. Hinzufügen neuer Schlüssel/Wert-Kombinationen ist jederzeit möglich. z.B. person[“geschlecht“] = “männlich“ ergänzt den obigen Hash um einen neue Schlüssel/Wert-Kombination. Symbole Symbole können als Labels verwendet werden um Daten zu identifizieren (wie auch Strings, wie wir oben gesehen haben) belegen aber weniger Speicherplatz als Strings da sie nur einmal gespeichert werden. Achtung nicht mit Variablen verwechseln! Symbole werden durch den Doppelpunkte gekennzeichnet und folgen darüber hinaus den Regeln der Variablennamen. Deshalb werden sie gerne als Schlüssel in Hashes verwendet. Wahrheitswerte (Booleans) Booleans werden wie gewohnt in Bedingungen benutzt um Kontrollstrukturen zu steuern. Diese Bedingungen werden durch Vergleichsoperatoren und logische Operatoren zusammengesetzt. Die Operatoren == (ist gleich) <, >, <=, >= sind bekannt. ! ist die logische Verneinung. Daraus ergibt sich != für Ungleichheit. Die logischen Operatoren && (and) und || (or) sind auch üblich. Wie gewohnt ist auch Klammerung möglich. Es gibt aber auch eine Reihe von Boolean-Funktionen in den unterschiedlichen Objekttypen wie z.B. .nil? für die Abfrage ob einen Variable nil (nicht definiert) ist oder .between?({Untergrenze},{Obergrenze}) für die Bestimmung ob ein Wert innerhalb gegebener Grenzen liegt oder .include?({Element}) um festzustellen ob ein Array ein Element enthält. Gemeinsam ist diesen Funktionen typischerweise das ? in der Funktionsbezeichnung dass auf einen Boolean-Funktion hinweist. Folgen (Ranges) Ranges sind Folgen von Zahlen oder Zeichen die sich aus einer einfachen Regel ergeben und wie folgt definiert werden: {Startwert}..{Endwert} also z.B. 1..3 ergibt 1,2,3. Will man auf Ranges Methoden anwenden muss man sie entweder Variablen zuweisen oder in runde Klammern setzen! .begin (.first) bzw. .end(.last) zeigen den Start- bzw. Endwert der Range an. Mit dem Splat-Operator (*) lassen sich Ranges in Arrays umwandeln. Z.B. [*(1..3)] ergibt das Array [1,2,3] Ranges funktionieren aber nicht nur mit Zahlen sondern auch mit Zeichen (z.B. “a“..“z“) oder Strings (“aa“..“zz“ – ja das liefert alle Kombinationen von aa,ab,ac,… bis zx, zy, zz!). Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 9 Konstanten Konstanten sind ähnlich Variablen jedoch sollen sie ihren Wert nicht während der Verarbeitung ändern. Ruby kennzeichnet Konstanten durch einen beginnenden Großbuchstaben. Test ist also eine Konstante während test eine Variable ist. Um Konstanten besser von Variablen unterscheiden zu können sollte man sie vollständig mit Großbuchstaben schreiben (also TEST). Außer dass Ruby eine Warnung von sich gibt ist jedoch das Verhalten von Variablen und Konstanten identisch. Kontrollstrukturen Verzweigungen (If, else elsif) Einige Eigenheiten von Ruby sind zu beachten. 1. Es ist keine Klammerung von Anweisungen nötig. 2. Elsif ist kein Tippfehler (das e bei else if wird weggelassen) Der Klassische Aufbau: If Bedingung1 Anweisungen für den Fall das Bedingung1 erfüllt ist elsif Bedingung2 Anweisungen für den Fall das Bedingung2 erfüllt ist (diese 2 Zeilen können sich beliebig oft wiederholen) else Anweisungen für den Fall das keine der obigen Bedingungen erfüllt ist end Wenn nur eine Anweisung bedingt ausgeführt werden soll kann diese Bedingung auch direkt nach der Anweisung angegeben werden. {Anweisung] if {Bedingung}. Z.B. puts “Ja“ if 2>1 gibt „Ja“ aus während puts “Ja“ if 2==1 keine Ausgabe erzeugt. Varianten dieser Verzweigung ergeben sich durch unless {Bedingung} (entspricht einem if !{Bedingung}) … end case {Testwert} when Wert 1 … when Wert 2 … else … end (entspricht dem switch in vielen Programmiersprachen) {Bedingung} ? { Anweisungen wenn wahr} : {Anweisungen wenn falsch} (Ternärer Operator) z.B. puts x==1 ? „eins“ : „nicht eins“ Für die optionale Zuweisung stehen 2 Varianten zur Verfügung x=y||z weist der Variablen x das Objekt y zu wenn es existiert (true ist) ansonst das Objekt y. x||=y weist der Variablen x das Objekt y zu wenn sie nil ist und belässt sie wenn sie nicht nil ist. Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 10 Schleifen (loop do, while, until) Hier sind wenige Überraschungen zu erwarten. Mit loop do … end wird eine (Endlos-)Schleife definiert. Um diese Schleife zu steuer gibt es die Kommandos break (Schleife verlassen), next (den nächsten Schleifendurchlauf beginnen), redo (den aktuellen Schleifendurchlauf neu starten), retry (den Schleifendurchlauf von neuem beginnen – von der ersten Schleife weg). Natürlich gibt es auch die Schleifen die die Abbruchbedingung schon enthalten (while, until). While und until arbeiten auch in einer Inlinevariante. Z.B. X=0 puts x+=2 while x<100 Iteratoren Iteratoren sind abzählbare Schleifen, also Schleifen mit einer bestimmten Anzahl an Durchläufen. Z.B: 5.times do puts “Hi“ end Andere Varianten mit demselben Ergebnis zeigen gleich einige mögliche Iteratoren: 1.upto(5) {puts „Hi“} oder 5.downto(1) {puts „Hi“} oder (1..5).each {puts „Hi“} Merke hier die Notation der Code-Blocks die jetzt nicht mit do … end sondern mit { … } erfolgt. Beide Schreibweisen sind austauschbar. Der Vorteil von Iteratoren ist, dass man deren Werte in den Schleifendurchläufen verwenden kann. Dies geschieht dadurch, dass man eine Schleifenvariable in Pipes nach dem do angibt, also z.B. 5.times do |x| puts x.to_s + “. Durchlauf” end Der each-Iterator ist speziell nützlich bei Arrays und Hashes, da er es ermöglicht die Elemente des Arrays (Hashes) einzeln abzuarbeiten. Nehmen wir als Beispiel ein Array a=[1,“a“,3,7,9] so würde die Codezeile a.each {|x| print x} die Anzeige „1a379“ und das Array als Ergebnis produzieren. Die Kommandos break, next, redo und retry funktionieren in Iteratoren ebenso. Code-Blocks Was sind Code-Blocks? Einfach gesagt sind Code-Blocks eine Gruppe von Anweisungen aber eventuell auch ein BooleanAusdruck, die durch die Schlüsselworte do und end eingefasst sind (die Kurzschreibweise { und } wird üblicherweise nur für einzeilige Blocks verwendet). Interessant sind diese aus 2 Gründen. Erstens kann man, wie oben gesehen, Blockvariablen verwenden, die nur innerhalb des Blocks gültig/sichtbar sind und andererseits (und viel wichtiger) sind Blocks für viele leistungsfähige Methoden nötig. Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 11 Suchen mit Hilfe von Code-Blocks Code-Blocks werden bei verschiedenen Suchmethoden verwendet und stellen dabei i.d.R. BooleanAusdrücke dar. .find {|var| var_Bedingung } findet das erste Vorkommnis eines Elements welches durch die Bedingung abgebildet wird (.detect ist ein Synonym für .find). Wird nichts gefunden liefert .find nil. Z.B.: (1..10).find {|i| i % 3 == 0) liefert den Wert 3 (der erste Wert der durch 3 teilbar ist). .find_all {|var| var_Bedingung } findet alle Vorkommnisse eines Elements welches durch die Bedingung abgebildet wird (.select ist ein Synonym für .find_all). Wird nichts gefunden liefert .find nil. Z.B.: (1..10).find_all {|i| i % 3 == 0) liefert die Werte 3,6,9 (alle durch 3 teilbar). .any? {|var| var_Bedingung } liefert ein true-Objekt wenn irgendein Element die Bedingung erfüllt andernfalls ein false-Objekt. .all? {|var| var_Bedingung } liefert analog ein true-Objekt wenn alle Elemente die Bedingung erfüllen. .delete_if {|var| var_Bedingung } entfernt aus einem Array jene Elemente, die die Bedingung erfüllen. Z.B.: [*1..10].delete_if {|i| i % 2 == 0} liefert als Ergebnis [1,3,5,7,9] zurück. Hashes verbinden mit Hilfe von Code-Blocks Code-Blocks können auch optional verwendet werden ein Beispiel ist die Anwendung bei der mergeMethode die bei Hashes ihre Anwendung findet. h1.merge(h2) verbindet die Elemente zweier Hashes miteinander. Alle Schlüssel die einmalig sind, bleiben im Ergebnis vorhanden, alle Schlüssel die doppelt vorkommen werden standardmäßig mit jenen Werten zurückgeliefert die in h2 stehen. Dieses Standardverhalten kann durch einen Code-Block verändert werden. So wird durch h1.merge {|key,old,new| old < new ? old : new} der jeweils kleinere Wert zurückgegeben. Merke dass hier 3 Blockvariablen angegeben sind, die erste ist der Schlüsselwert, die zweite der alte Wert (h1) und die dritte der neue Wert (h2). h1 und h2 bleiben in dieser Variante unverändert. Mittels h1.merge!(h2) erhält h1 das Ergebnis der Operation zugewiesen. Ranges, Arrays und Hashes mit Hilfe von Code-Blocks verarbeiten Mit Hilfe der Methode .collect {|var| Anweisungen} (oder .map welches Synonym verwendet werden kann) können Anweisungen auf ein Array (eine Range oder einen Hash) angewandt werden. Das Ergebnis der Anweisungen wird dann als Ergebnis für jedes Element des Arrays (Ranges oder Hashes) als Arrayelement (auch bei Ranges und Hashes) zurückgegeben. Es gilt der Grundsatz dass die Anzahl der Elemente des Ausgangsarrays (-Ranges, -Hashes) gleich der Anzahl der Elemente des Ergebnisarrays ist. (1..5).collect {|n| n*10} liefert als Ergebnis [10, 20, 30, 40, 50] liefert als Ergebnis [nil, „B“, nil] da für die Fälle x==“a“ und x==“c“ keine Auswertung von x.capitalize erfolgt. Das gewünschte Ergebnis [“a“, “B“, “c“] liefert hingegen [“a“, “b“, “c“].map {|x| x ==”b” ? x.capitalize : x } [“a“, “b“, “c“].map {|x| x.capitalize if x ==”b”} Im Falle der Anwendung bei Hashes ist zu beachten dass 2 Blockvariablen (Schlüssel und Wert) übergeben werden. Z.B. h = {:a => 1, :b => 2 } h.map {|k, v| "#{k}: #{v*10}"} liefert als Ergebnis das Array mit den 2 Elementen ["a: 10", "b: 20"] Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 12 Sortieren mit Hilfe von Code-Blocks Mit dem Vergleichsoperator <=> (dem sog. Spaceship-Operator) können 2 Objekte verglichen werden. Als Ergebnis des Vergleiches gibt der Vergleichsoperator 3 mögliche Werte zurück. Wert 1 <=> Wert 2 Wert 1 kleiner Wert 2 Wert 1 gleich Wert 2 Wert 1 größer Wert 2 Ergebnis -1 0 1 Die .sort-Methode sortiert mit Hilfe dieses Operators. Man kann aber die Standardsortierung durch Codeblocks modifizieren. Die Sortierung für numerische Werte ist aufsteigend. array.sort und array.sort {|v1, v2| v1 <=> v2} sind gleichwertig. Will man die Sortierung umkehren kann man dies auf 2 Arten: array.sort.reverse oder array.sort {|v1, v2| v2 <=> v1}. Die Standardsortierung von Strings ist alphabetisch aufsteigend. Will man jedoch Strings z.B. nach ihrer Länge sortieren hilft nur noch ein Code-Block. obst = [“pfirsiche”, “bananen”, “birnen”] obst.sort {|f1, f2| f1.length <=> f2.length} liefert [“birnen”, “bananen”, “pfirsiche”] Aber es wäre nicht Ruby gäbe es dafür nicht auch einen kürzeren Weg: obst.sort_by {|f| f.length} Werte akkumulieren mit Hilfe von Code-Blocks Die Methode .inject {|memo,n| Operation mit memo und n} ermöglicht das akkumulieren von Werten über ein Array (Range, bedingt Hash). Memo fungiert dabei als Akkumulatorvariable deren Endwert dem Ergebnis der inject-Operation entspricht. (1..5).inject {|m,n| m+n} liefert das Ergebnis 15 (=1+2+3+4+5). Der Startwert von memo ist standardmäßig 0 kann aber mit .inject(Startwert) auch auf einen anderen Wert gesetzt werden. Wie gewohnt funktioniert die Akkumulation auch mit anderen Datentypen als numerischen. z.B.: ("aa".."af").inject {|m,n| m+n} liefert "aaabacadaeaf" Achtung, auch hier muss in jeder Iteration ein gültiger mit der Operation kompatibler Wert ermittelt werden (siehe collect). Methoden Definition uns Aufruf von Methoden def methodenname (… Code der Methode) end … definiert eine Methode mit dem Namen „methodenname“ wobei aus Kleinbuchstaben besteht. Methoden werden üblicherweise in eigenen Files mit der Endung .rb abgelegt. Sowohl in irb als auch in anderen Files kann mittels require „Filename“ die Methodendefinition geladen werden (auf Pfad achten). Methoden müssen im Code vor deren Benutzung definiert sein (also in einer früheren Zeile). Methoden werden einfach über ihren Methodennamen aufgerufen. Definition von Argumenten für Methoden Argumente werden einfach als durch Komma getrennte Variablenliste optional mit einem Defaultwert versehen hinter dem Methodennamen in Klammern angeführt. Z.B. def addiere (n1, n2=0) puts n1 + n2 end Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 13 Definition von Rückgabewerten in Methoden Methoden liefern automatisch das Ergebnis der letzten Operation der Methode als Return-Value. Will man das übersteuern oder explizit kennzeichnen kann man die Anweisung return Rückgabewert angeben. Dies führt auch automatisch zur Beendigung der Methode. Will man mehrere Rückgabewerte in einer Methode realisieren, so kann man dies über ein Array als Rückgabewert verwirklichen. Z.B.: def add_and_sub (n1=0, n2=0) return [n1+n2, n1-n2] end Eine nette Eigenschaft von Ruby ermöglicht es das rückgegebene Array (welches im obigen Beispiel aus 2 Rückgabewerten besteht) auch gleich mehreren Variablen (hier 2) zuzuordnen. Z.B.: add, sub = add_and_sub(10,7) Nach dieser Zeile enthält add den Wert 17 und sub den Wert 3. Operationen sind auch Methoden Wenn wir eine Operation betrachten müssen wir beachten, dass diese ebenso Methoden sind. 10 + 2 ist eigentlich 10.+(2) also die Methode + des Integer-Objekts 10 mit dem Parameter 2. Dies gilt ebenso für -, *, /, %, <<, [], usw. Interessant ist das bei einem Array. Die Zuweisung array[2]=“x“ ist eigentlich so zu lesen die Methode []= wird auf das Array array angewandt mit den Parametern 2 und „x“ also array.[]=(2,“x“). Ruby versteht aber das für uns wesentlich besser lesbare Format array[2]=“x“ und wandelt es intern in die oben gezeigte Form um. Genau dieses Verhalten bezeichnet man als Syntactic Sugar! Klassen Definition und Instanzierung von Klassen class Klassenname … end Die Definition von Klassen erfolgt sehr ähnlich Methodendefinitionen jedoch mit dem Schlüsselwort class und (wichtig!) einem Klassennamen der mit einem Großbuchstaben beginnt (mehrere Wörter werden durch die CamelCaseSchreibweise getrennt). Innerhalb von Klassen lassen sich wie gewohnt Methoden definieren die dadurch zu Klassenmethoden werden. Klassen werden instanziert durch die Methode new. Um mit Objekten arbeiten zu können müssen sie Variablen zugewiesen werden. Die typische Form ist variable = Klasse.new Definition von Attributen in Klassen Instanzvariablen werden durch das @ Symbol gekennzeichnet und sind in Klassen gekapselt, können also ausschließlich über Methoden zugegriffen werden (Setter und Getter). Z.B.: class Person def set_name(name) @name = name end def get_name @name end end Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 14 Um nun eine Instanzvariable zu setzen muss man in unserem Beispiel (nachdem man mit person = Person.new eine Instanz generiert hat) die Methode person.set_name(„Franz Meier“) aufrufen. Um den Wert zu erhalten gibt man z.B. puts person.get_name an. Um das Verhalten natürlicher zu gestalten kann man auch die Getter und Setter Methoden komfortabler definieren (Syntactic Sugar): class Person def name=(name) @name = name end def name @name end end Nun kann man (nach Instanzierung) mit person.name=”Franz Meier” die Setter-Methode aufrufen wie wenn man auf das Attribut direkt zugreifen könnte. Und erwartungsgemäß funktioniert nun auch puts person.name Und es wäre nicht Ruby wenn das nicht auch noch kürzer ginge. Und hier ist es: class Person attr_accessor :name end Will man nur eine Getter-Methode schreibt man attr_reader :name, will man nur eine SetterMethode schreibt man attr_writer :name. Und natürlich kann man auch mehrere solche Instanzvariablenmethoden auf einmal definieren, z.B.: attr_accessor :name, :plz, :ort, :strasse Initialisierungsmethoden Wird in einer Klasse eine Methode mit dem Namen „initialize“ definiert so wird diese automatisch bei der Instanzierung des Objekts aufgerufen. Enthält diese Methode Parameter können diese mittels Angabe der Parameter beim Aufruf von „new“ übergeben werden. Klassenmethoden und -attribute Eine Klassenmethode ist eine Methode die auf der Ebene einer Klasse und nicht auf der Ebene eines Objekts (einer Instanz der Klasse) aufgerufen wird. Die bekannteste Klassenmethode ist „new“. Eine Klassenmethode wird genauso definiert wie eine normale Instanzmethode jedoch wird vor dem Methodennamen der Ausdruck „self.“ angeführt. Der Zusatz self kennzeichnet in jedem Anwendungsfall das gerade instanzierte Objekt (innerhalb einer Instanzmethode) oder die Klasse selbst (im Fall der Methodendefinition und innerhalb von Klassenmethoden). Klassenmethoden werden für Aufgaben benutzt, die unabhängig von den Instanzen bzw. über mehrere Instanzen der Klasse gehen. Will man Informationen über die Klasse in einer Variablen speichern benutzt man Klassenvariablen die durch das Präfix „@@“ gekennzeichnet werden. Initialisiert werden diese Variablen typischerweise am Beginn einer Klasse noch vor den Klassen- und Instanzmethodendefinitionen einfach durch ´Zuweisung des Initialwertes. Z.B. @@anz_instanzen = 0 Verwendet werden die Klassenvariablen wie normale Variablen mit dem Unterschied, dass es sie nur einmal pro Klasse gibt. Z.B. (für das Zählen von Instanzen) def initialize @@anz_instanzen += 1 end Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 15 Für Klassenvariablen gilt dasselbe wie für Instanzvariablen, auf sie kann nur mit Hilfe von Methoden zugegriffen werden. Diese werden als Klassenmethoden (mit self.) definiert und genauso wie die Getter und Setter bei den Instanzvariablen gestaltet. Leider gibt es in Core-Ruby derzeit noch keine Kurzvariante wie bei den Instanzvariablen (in Ruby on Rails gibt es cattr_accessor). Da aber Klassenvariablen seltener vorkommen ist dies nicht so tragisch. Unser Beispiel sieht demnach also wie folgt aus: def self.anz_instanzen @@anz_instanzen end def self.anz_instanzen=(wert=0) @@anz_instanzen = wert end Vererbung Wie in objektorientierten Programmiersprachen üblich kann man Klassen (Kind- oder Subklassen) von anderen Klassen (Eltern- bzw. Superklassen) ableiten. Dadurch übernimmt die Subklasse alle Eigenschaften der Superklasse. Subklassen werden wie folgt definiert: class subklasse < superklassse Im Unterschied zu vielen anderen objektorientierten Programmiersprachen unterstützt Ruby keine Mehrfachvererbung (das gewünschte Verhalten kann jedoch mit Modulen weitgehend simuliert werden). Subklassen können jede Methode der Superklasse überschreiben in dem einfach eine neue Definition einer Methode angeführt wird. Die jeweils letzte Definition in sequentieller Abfolge zählt. Dieses Verhalten gilt auch für Klassen. Es können also Klassendefinitionen immer wieder neu geschrieben werden und dadurch auch überschrieben werden. Das funktioniert sogar bei Ruby-Core Klassen. Ein Beispiel: wir starten irb –simple-prompt >> X = [1,2,3] => [1, 2, 3] >> x.to_s => „123“ Das ist das Standardverhalten. Nun schreiben wir die originale to_s Methode der Array-Klasse um: >> class Array >> def to_s >> self.join(‘,‘) >> end >> end => nil >> x.to_s => “1, 2, 3” Eine sehr leistungsfähige Sache! Möchte man in einer Subklasse die Methode umschreiben aber auf die Methode der Superklasse zugreifen verwendet man „super“, welches die entsprechende namensgleiche Methode der Superklasse aufruft. Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 16 Module Namensräume Module sind ähnlich wie Klassen Hüllen um eine Menge Programmcode können aber im Gegensatz zu Klassen nicht instanziiert werden. Module werden oft im Zusammenhang mit Klassen verwendet, da sie zur Definition von Namensräumen (namespaces) verwendet werden können und dadurch ermöglichen Namenskonflikte (von eventuell gleichnamigen Klassen in unterschiedlichen Bibliotheken) zu verhindern. Der Namensraum wird einfach dadurch definiert, dass die Klasse in ein Modul „eingepackt“ wird. Etwa so: module Modulname class Klassenname …. end end Zugegriffen wird auf die Klasse dann mit Modulname::Klassenname Mixins Da es in Ruby keine Mehrfachvererbung gibt, verwendet man Module (sogenannte Mixins) zur Realisierung mehrfach verwendeter Codeelemente. Der durch ein Modul definierte Codebereich wird mit der Anweisung include Modulname an der Stelle im Code eingefügt an der die Includeanweisung steht. Diese Module eigenen sich auch bestens als Code-Bibliotheken. In diesem Fall sind die Anweisungen load und require zu erwähnen. Load dient dazu solche Bibliotheken zu einem bestehenden Code dazu zu laden (jedes mal wenn load aufgerufen wird). Wenn man dies aber öfters tut ist das Speicherplatzverschwendung. Require funktioniert ähnlich, jedoch lädt es das File nur einmal in den Speicher und kann feststellen ob ein File schon geladen ist. Beide Anweisungen haben die Form: load/require ‘Pfad zu Rubycodedatei‘ Sie liefern true wenn eine Datei geladen wurde, andernfalls false. Filehandling Grundlagen Input/Output Einfache Ausgabemethoden haben wir ja schon kennen gelernt: puts … gibt was immer man danach angibt als Ausgabe aus inklusive einem Zeilenvorschub. print … macht dasselbe jedoch ohne Zeilenvorschub. Die einfachste Eingabemethode ist gets. Mit gets wartet Ruby auf eine Eingabe des Benutzers und liefert diese als Ergebnis der gets-Methode zurück. Beachte, dass das Ergebnis auch das Zeilenvorschubzeichen (in der Regel „\n“) enthält. Um dieses zu entfernen kann man die Methode chomp verwenden. Eine typische Eingabe sieht also wie folgt aus: mein_input = gets.chomp Diese Methoden sind auch anwendbar beim Umgang mit Files. Dazu gibt es in Ruby die IO-Klasse und deren Subklasse File. Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 17 Filesystem: mögliche Probleme in Cross-Platform-Environments Übliche Probleme beim Umgang mit dem Filesystem betreffen „Cross-Platform“-Unterschiede. Diese betreffen in der Regel Seperatoren und Zugriffsrechte. Die Seperatoren zwischen den Directories in Windows- (\) bzw. Linux-basierten (/) Systemen sind unterschiedlich. Unter Ruby verwendet man in der Regel den Forwardslash (/) der auch unter Windowssystemen richtig interpretiert wird. Besser ist jedoch die Nutzung der File.join-Methode in der einfach alle Bestandteile des Pfades als Parameter angegeben werden. Z.B.: File.join(“ruby“, “myprogs“, “myfile.rb“) unter Linux(MacOSx, ..) wird daraus ruby/myprogs/myfile.rb und unter Windows wird daraus ruby\myprogs\myfile.rb Will man einen absoluten Pfad erhalten so gibt man als ersten Bestandteil eine Leeren String ““ an z.B. File.join(“ruby“, “myprogs“, “myfile.rb“) erzeugt unter Windows \ruby\myprogs\myfile.rb Beim lokalen Arbeiten mit Files wird es in der Regel keine Probleme geben, da man hier meist Owner ist und alle Rechte (Lesen, Schreiben, Ändern, Löschen, Ausführen, etc.) besitzt. In Netzwerken ist dies häufig nicht so weswegen hier auf die Rechte und Eigentümerschaft geachtet werden muss. Unter Windows-Systemen wir dies über das Eigenschaftenfenster der Dateien oder ab Windows Vista über die Commandline-Befehle Takeown.exe (wenn Administratorrechte erteilt werden sollen auch noch icacls.exe) und cacls.exe. Unter Unix-basierten Systemen heißen die entsprechenden Kommandos chown bzw. chmod. Grundlegendes zu Filepfaden Wie gewohnt können in Ruby-Programmen relative und absolute Pfade verwendet werden. Bei relativen Pfaden gibt „./“ Das aktuelle Directory und „../“ das übergeordnete Directory an. Um festzustellen welches der aktuelle Pfad ist stellt Ruby die Konstante __FILE__ zur Verfügung, die den Filenamen des aktuellen Files enthält. Um nun den absoluten Pfad des aktuellen Files zu erhalten gibt man FILE.expand_path(__FILE__) an und bekommt diesen inklusive Dateinamen zurückgeliefert. Will man nur das Directory des aktuellen Files so gibt man File.dirname(__FILE__) an. Dieses liefert den relativen Pfad des angegebene Files den man als Ausgangspfad für alle Fileoperationen verwenden kann. Hinweis: Enthält der Pfad ein Leerzeichen muss dieses mit \ markiert werden aus dem Directory “mein file“ wird “mein\ file“ (Achtung Doppelte Anführungszeichen sind hier wichtig!). Dateizugriff Mit File.new wird ein neues File-Objekt angelegt und auch gleichzeitig das File auf dem Speichermedium angelegt. Die übliche Form der File.new-Methode hat folgende Struktur: myfile = File.new (‘Dateiname‘,‘Modus‘) # Hier kommen die Fileoperationen myfile.close Alternativ kann man auch die File.open verwenden (ist übersichtlicher und mehr Ruby-like) File.open (‘Dateiname‘,‘Modus‘) do |myfile| # Hier kommen die Fileoperationen end Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 18 Die Modi beim Filezugriff sind: r w a Lies vom Start weg (Datei muss existieren) (Über-)schreib File vom Start (legt neues File an) Schreibt Daten an das Ende eines bestehenden Files r+ w+ a+ Lesen und Schreiben (vom Start weg) Lesen und Schreiben (destruktiv) Lesen und Schreiben (am Ende) Schreiben von Dateien Um auf Dateien zu schreiben kann man die schon bekannten Methoden puts (mit Zeilenvorschub) und print (ohne Zeilenvorschub verwenden, die man einfach als Methoden des instanziierten Files aufruft. myfile.print “abcdefg“ myfile.puts “BLABla“ Beide Methoden liefern als Ergebnis das nil-Objekt zurück. Es gibt aber noch 2 weitere Varianten wie man in Dateien schreiben kann: … entspricht print liefert aber als Ergebnis die Anzahl der geschriebenen Myfile.write „abcdefg“ Zeichen zurück myfile << „abcdefg“ … entspricht ebenfalls print liefert aber als Ergebnis das File-Objekt zurück Lesen von Dateien Lesen von Dateien ist ebenfalls mit der schon bekannten Methode gets möglich: zeile = myfile.gets Die Methode gets liest dabei alle Zeichen bis zum nächsten Zeilenumbruch. Achtung der Zeilenumbruch ist in zeile enthalten und sollte daher mit der chomp.Methode entfernt werden. Da man jedoch beim Ende der Datei als Ergebnis der gets-Methode nil zurückgeliefert bekommt und nil die chomp-Methode nicht kennt sollte man eine Überprüfung einbauen, etwa: zeile = (zeile==nil) ? ““ : zeile.chomp Oder mit einer Leseschleife verbunden: File.open (‘file.txt‘,‘r‘) do |myfile| while line = myfile.gets puts line.chomp end end <- Diese Schleife wird durchgeführt solange file.gets ungleich nil ist <- erst hier chomp da jetzt sicher ein Text in line ist Will man jede Zeile einer Datei lesen so gibt es auch eine kürzere Schreibweise für obiges Beispiel: File.open (‘file.txt‘,‘r‘) do |myfile| myfile.each_line {|line| puts line.chomp } end Eine weitere Möglichkeit aus Dateien zu lesen ist die read-Methode mit der man die als Parameter übergebene Zahl an Zeichen aus der Datei lesen kann myfile.read(10) liest die nächsten 10 Zeichen der Datei. Achtung: Auch Zeilenvorschübe (\n) werden mitgezählt. Der Filepointer Will man gezielt in Dateien schreiben oder aus ihnen Lesen benutzt man den Filepointer, der ähnlich dem Cursor in einer Textverarbeitung die aktuelle Position in der Datei anzeigt. Beachte dass bei Schreiboprationen die Zeichen an der aktuellen Position überschrieben werden und nicht eingefügt. Mit myfile.pos kann man die aktuelle Position des Filepointers bestimmen (das erste Zeichen hat die Position 0) und mit myfile.pos = 10 kann man z.B. den Filepointer auf das 11. Zeichen setzen. Springt Ruby – Einführung Gesammeltes für das gemeinsame Studium Seite 19 man auf eine Position, die im File nicht enthalten ist erfolgt keine Fehlermeldung. Read bzw. gets liefert dann nil als Ergebnis und write (etc.) fügt bis zur Position nill-Charakter ein . myfile.rewind entspricht myfile.pos = 0. Außerdem setzt rewind die lineno auf 0. Was ist lineno? Mit der Methode lineno kann ein interner Zähler der durch die gets (und die readline)-Methode bei jedem Aufruf um 1 erhöht wird, abgefragt werden. Benutzt man konsequent gets zum Einlesen der Daten entspricht lineno der Zeilennummer (bei 0 beginnend). myfile.eof? prüft ob das Ende der Datei erreicht ist. Umbenennen, Löschen und Kopieren von Dateien Dazu dienen einfach die 2 Methoden File.rename (mit 2 Parametern: alter Name, neuer Name) und File.delete (mit dem Filenamen als Parameter). Wichtig ist dabei zu beachten, dass man für die Operationen auf der Dateiebene die nötigen Berechtigungen hat. Will man Files kopieren muss man zuerst mit require eine Standardbibliothek einbinden. Require ‘fileutils‘ FileUtils.copy(‘from_file.txt‘,‘to_file.txt‘) Die FileUtils-Klasse hat neben der copy-Methode (kurz cp) auch noch eine Move- (kurz mv-) und eine remove-(rm-)Methode. Außerdem sind die meisten Unix-Commandos über FileUtils zugänglich (cd, mkdir, rmdir, chmod, chown, pwd, ln, touch). Weitere Operationen mit Files und Directories File.exists?(myfile) … liefert true wenn das File (oder Directory) existiert File.file?(myfile) … liefert true wenn myfile ein File (und z.B. kein Directory) ist File.directory?(myfile) … liefert true wenn myfile ein Directory ist File.readable?(myfile) … liefert true wenn myfile ein File ist, das gelesen werden kann File.writeable?(myfile) … liefert true wenn myfile ein File ist, das geschrieben werden kann File.executeable?(myfile) … liefert true wenn myfile ein File ist, das ausgeführt werden kann File.size(myfile) … liefert die Dateigröße in Byte File.mtime(myfile) … liefert die Zeit zurück an der die Datei zuletzt modifiziert wurde File.atime(myfile) … liefert die Zeit zurück an der die Datei zuletzt zugegriffen (gelesen oder geschrieben) wurde File.ctime(myfile) … liefert die Zeit zurück an der die Datei zuletzt ihren Status änderte (gelesen, geschrieben oder eine Veränderung bei Eigentümer, Gruppe oder Rechten erfuhr) All diese Methoden sind über das stat Objekt innerhalb einer Instanz der Klasse File ebenfalls verfügbar. File.size(myfile) entspricht also myfile.stat.size. Die Dir-Klasse eröffnet uns den Zugriff auf Directories. Mit Dir.foreach(‘.‘) {|entry| puts entry} bekommen wir beispielsweise eine Liste aller Dateien und Subdirectories des aktuellen Directories. Ruby – Einführung Gesammeltes für das gemeinsame Studium Grafiklibraries 1. TK, evtl. GTK, evtl. FXRuby Seite 20 Ruby – Einführung Gesammeltes für das gemeinsame Studium Codebeispiele Primzahlensieb: print "Primzahlen bis:" g=STDIN.gets x=(2..g.to_i).to_a y=[] while x.count > 0 do y << x.shift x.delete_if { |i| i % y.last == 0} end y.each { |i| print i.to_s + ", " } Seite 21