Ruby Weblog

Winfried Mueller
www.reintechnisch.de

Wer Skriptsprachen und Objektorientierung mag, findet in Ruby eine ästhetische Ausdrucksmöglichkeit seines Könnens. Plattformübergreifend.


22.12.2014 Ruby Gem Installationen unter Windows klappen nicht

Gibt ein SSL-Error, wenn man versucht, irgendwelche Gems zu installieren. Installierte Ruby-Version ist 2.1.5p273 über rubyinstaller.org gezogen.

Hier ist die Lösung: https://gist.github.com/luislavena/f064211759ee0f806c88

Konkret bedeutet das, einfach das Zertifkat https://raw.githubusercontent.com/rubygems/rubygems/master/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem herunterladen und unter c:\path_to_ruby\lib\ruby\2.1.0\rubygems\ssl_certs installieren. Dann sollte alles klappen.

08.11.2013 Design by Contract

Ein etwas älterer Artikel aus 2004, den ich aber hier nochmal konservieren möchte:

Design by Contract

Dieses Konzept stammt von Betrand Meyer, dem Erfinder der Programmiersprache Eiffel. Er hat sich viel Gedanken darüber gemacht, wie man besonders robuste und fehlerfreie Software entwickeln kann bzw. wie eine Sprache dieses Vorhaben unterstützen kann.

Seine Ideen haben mich inspiriert, auch in anderen Programmiersprachen das Design-by-Contract Paradigma einzuführen. Kurz zusammengefasst könnte man dieses Paradigma so beschreiben:

  • ein Objekt kümmert sich immer darum, in einem konsistenten Zustand zu bleiben. Es muss also so designt werden, dass man es von außen niemals in einen fehlerhaften Zustand versetzen kann.
  • ein Objekt erfüllt den Vertrag, wenn es sich an vereinbarte Regeln hält. Diese Regeln werden durch ensure-Klauseln sichergestellt. Solche Regeln betreffen einerseits die Außenbeziehung, was es also für Werte zurückgibt wie auch die inneren Zustände.
  • ein Objekt hat auch Anforderungen an die Umwelt, auf eine bestimmte Weise behandelt zu werden. Es überprüft durch require-Klauseln, ob übergebene Werte den Anforderungen entsprechen.
  • Kommt es irgendwo zu einer Vertragsverletzung, wird eine Exception ausgelöst.

In Ruby habe ich mir hierzu folgende Methoden definiert:

 
class AssertError    < StandardError; end
class RequireError    < StandardError; end
class EnsureError    < StandardError; end

def x_assert( dsc="" )
  begin
    raise AssertError, "Assert: #{dsc}"
  rescue =>exc
    new_backtrace = exc.backtrace
    new_backtrace.shift
    exc.set_backtrace( new_backtrace )
    raise
  end
end


def x_require( dsc="" )
  begin
    raise RequireError, "Require: #{dsc}"
  rescue =>exc
    new_backtrace = exc.backtrace
    new_backtrace.shift
    exc.set_backtrace( new_backtrace )
    raise
  end
end

def x_ensure( dsc="" )
  begin
    raise EnsureError, "Ensure: #{dsc}"
  rescue =>exc
    new_backtrace = exc.backtrace
    new_backtrace.shift
    exc.set_backtrace( new_backtrace )
    raise
  end
end

  • Beim Eintritt in eine Methode überprüfe ich die übergebenen Werte und werfe mit x_require ab, falls etwas nicht stimmt.
  • Beim Austritt aus einer Methode checke ich den Rückgabewert und werfe ggf. mit x_ensure ab
  • Beim programmieren kommt es immer mal wieder vor, dass man bei bestimmten Programmpassagen genau weiß, es darf hier nicht passieren, dass dieser oder jener Zustand auftritt. Für solche Fälle gibt es unter C/C++ das Makro assert, was bestimmte Zustände überprüft. In Ruby nutze ich hierfür x_assert, falls ein Wert oder Zustand nicht korrekt ist. Ich baue x_assert sehr häufig ein, um immer wieder Überprüfungen zu machen, ob mein Programmcode noch das tut, was ich erwarte. So finde ich sehr frühzeitig Fehler, die sonst gar nicht auffallen oder erst sehr verzögert zu Folgefehlern führen.
  • asserts sind eher für die Debugphase gedacht, man kann es als "Debugcode" bezeichnen. Dagegen können ensure und require auch im endgültigen Code enthalten sein. Man muss auf jeden Fall aufpassen, dass man assert-Code vom restlichen Programm klar trennt, bzw. das Programm muss vollständig sein, wenn man z.B. die assert-Zeilen auskommentiert. Überhaupt sollte man normalen Programmfluß und Ausnahmebehandlung gut voneinander trennen.
  • ich habe absichtlich die Prüfung nicht in x_require, x_ensure, x_assert mit reingenommen, weil das mehr Laufzeit kosten würde.
  • wenn der Code wirklich gut getestet ist und man Laufzeit sparen muss, kann man z.B. mit einem kleinen Skript alle x_asserts ausdokumentieren. Gleiches gilt für x_require oder x_ensure. Man kann auch das Verhalten dieser Methoden ändern, in dem man ein andere Datei mit require hineinlädt.
  • Design by Contract hat eine wunderbare dokumentierende Eigenschaft. Wer den Code liest, weiß sofort, was Methoden erwarten und was sie zurückgeben sollten. Und man sieht, welche Zustände nicht erlaubt sind. Das alles macht den Code verständlicher. Gerade bei Ruby-Programmen ist die Gefahr sehr groß, dass man an Methoden Werte übergibt, die vom falschen Typ sind. Oder man kann aus Klassendefinitionen nicht herauslesen, welcher Typ denn eigentlich erwartet wird.

Beispiel:

 
  require "wmclasslib/dbg"     # hier stehen die x_ Methoden drin

  def myFunction( a, b )
    x_require unless a.class == String   # a muss String sein
    x_require unless b.class == Fixnum   # b muss Fixnum sein
    test = nil
    #...
    x_assert unless test != nil  # test muss hier ungleich nil sein
    #...
    x_ensure unless rval > 10    # return value muss immer > 10 sein
    rval  
  end


08.11.2013 Ruby ODBC-Zugriff unter Windows

Früher war alles einfach. Da gab es den One-Click-Installer und mit ihm wurden viele sinnvolle Pakete mitinstalliert, so auch ODBC-Zugriff. Mittlerweile hat sich die Strategie geändert, die ja eigentlich auch sinnvoll ist: Anstatt so ein großes Gesamtpaket zu warten, installiert der aktuelle Ruby-Windows-Installer nur noch das blanke Ruby.

Wäre ja alles nicht so schlimm, wenn man den Rest mal eben mit gem install draufschubsen könnte. Bei den ODBC-Sachen ist es allerdings umständlicher. Wenn man weiß, wie es geht, funktioniert es aber trotzdem recht schnell:

Zuerst einmal installiert man folgende Pakete nach:

  • gem install dbi
  • gem install dbd-odbc

Jetzt braucht es noch die kompilierten ODBC-Treiber. Die findet man z.B. hier als zip-Datei: http://www.ch-werner.de/rubyodbc/

In dieser Zip befinden sich die Dateien odbc.so und odbc_utf8.so, die man nun in das Verzeichnis ...\lib\ruby\1.8\i386-mingw32 hineinkopiert.

Das wars schon. Getestet mit ruby 1.8.7-p374 von http://rubyinstaller.org.

Weblinks:

28.01.2010 Ruby-Mysql für Ruby 1.8.4

Permalink

Es ist gar nicht so einfach, noch ein für Ruby 1.8.4 (Ubuntu Dapper) kompatibles ruby-mysql zu finden. Die Historie dieses Projekts ist nirgendwo mehr vollständig zu finden. Auf github findet man nur die aktuelle Version 2.9.x, die mindestens Ruby 1.8.7 braucht.

Die letzte Version, die noch mit 1.8.4 laufen sollte, scheint mir die 0.2.6 oder 0.2.7 zu sein. Die 0.2.6 findet man hier, wenn man schnell genug im Browser auf Stop klickt, damit die eingerichtete Weiterleitung nicht aufgerufen wird. Oder man nutzt diesen Direktlink.

Die Version 0.2.7 findet sich an anderer Stelle auf github. Sie soll auf jeden Fall unter Ruby 1.8.6 laufen, ein erster Test auf Ruby 1.8.4 war aber erfolgreich.

Unter Ubuntu Dapper braucht es jedoch eine Anpassung. Die Zeile 29 von mysql.rb versucht den mysql Socket an falscher Stelle zu suchen.

 
unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR

ändern in 
unix_socket = "/var/run/mysqld/mysqld.sock"

Interessant an ruby-mysql ist, dass es im Gegensatz zu mysql-ruby nativ in Ruby programmiert ist, also keine Kompilierung von C-Code braucht. Damit wird es gut auf Systemen einsetzbar, wo man keine Kompiliermöglichkeit zur Verfügung hat, z.B. auf fremd gehosteten Webservern.

Weblinks:

28.01.2010 Low-Level Webentwicklung

Permalink

Ich brauch ein paar kleine Werkzeuge mit Weboberfläche. Nachdem ich vor 3 Jahren schonmal einen Versuch startete, mich in Rails einzuarbeiten und daran glaubte, damit ganz schnell und unkompliziert Webanwendungen zu schreiben, will ich jetzt nicht wieder den Fehler machen und auf diesen Zug aufspringen. Damals investierte ich etwa 200 Stunden und ja, es sind auch erste lauffähige Anwendungen dabei rausgekommen. Und doch war mein Gefühl, dass ich mindestens nochmal 1000 Stunden hätte reinstecken müssen, um mit Rails wirklich sattelfest zu werden. Auch Rails ist keine Zauberwaffe. Auch wenn manches im Entwicklungsprozess verlockend einfach wird, gibt es viele Baustellen, wo man ewig rumfummelt.

Apropos Baustelle - ich war erschreckt, wie extrem sich in den letzten Jahren rund um Rails alles verändert hat. Meine Bücher, die gerade mal 3 Jahre alt sind, sind hoffnungslos veraltet. Viele neue Projekte rund um Rails sind aufgetaucht. Ich kann mir vorstellen, dass viele eine Menge Spaß daran haben, jeden Tag neue spannende Dinge auszuprobieren. Für mich ist das derzeit eher nichts. Ich will ein System, was sich schon so weit stabilisiert hat, dass ich auch in 5 Jahren mit meinem Know-How noch was anfangen kann. Und ich hab nicht die Zeit, sämtliche Projekte ständig an den neuesten Stand anzupassen.

Man muss sich mal klarmachen, wie viel Zeit man damit verbringt, immer auf dem neuesten Stand zu bleiben. All die Mailinglisten, Foren und Weblogs, die man durchforstet, all die Bücher und Videos, die man studiert, nur um etwas zu begreifen und unter Kontrolle zu haben, was in einem Jahr schon wieder veraltet ist. Jetzt macht man schon wieder alles ganz anders - vielleicht etwas besser und faszinierender, aber wieviel Bedeutung hat das neben dem Spielreiz wirklich für die reale Softwareentwicklung? Kann man schlussendlich all diese Zeit wieder einsparen, weil nun alles viel leichter wird? Ich bin da skeptisch, es sei denn, ich mach den ganzen Tag nichts anderes, als Webentwicklung mit Rails.

Ich will jetzt mal einen anderen Weg einschlagen: Mit ein paar einfachsten Techniken eine Webanwendung zusammenzimmern. Das Zielsystem gibt auch nicht viel her, es läuft noch ein relativ altes Ubuntu Dapper mit Ruby 1.8.4 auf einem 700MHz Server. Dort lässt sich auch nur die gute alte cgi-Schnittstelle verwenden.

Hauptproblem bei vielen neueren Bibliotheken ist die lange anfängliche Ladezeit, womit sie sich nicht für cgi-Webanwendungen eignen. Ich wollte z.B. das interessante Haml zum rendern einsetzen, aber nur das require "haml" dauert schon 4-5 Sekunden. Ähnlich erging es mir damals mit ActiveRecord - das ist alles nicht für cgi geeignet, wo bei jedem Aufruf ein neuer Ruby-Interpreter gestartet wird und erstmal alles laden muss. Der erb + ruby-mysql + cgi lädt hingegen in <1 Sekunde, dass ist brauchbar. Bei den Anwendungen geht es auch um Intranet-Sachen, wo nur wenige Nutzer gleichzeitig drauf zugreifen. Da macht es nichts, wenn mal einige wenige Interpreter parallel laufen.

Froh bin ich übrigens, dass das Entwicklungstempo bei Ruby selbst nicht so schwindelerregend ist. Ich werd wohl noch 3-4 Jahre mit dem 1.8er Zweig arbeiten können. Das Know-How, was ich mir vor 7 Jahren angeeignet habe, ist auch heute noch fast genauso gültig. Und 2014 freue ich mich dann, das bis dahin gut stabilisierte Ruby 1.9.x kennenzulernen.

24.01.2010 Haml Online Renderer

Permalink

Zum schnellen Ausprobieren für HAML-Code: http://rendera.heroku.com/


<< | RubyWeblog | Archiv 2007 >>