Syntax-Highlighting mit Coderay

Letztens schrob ich, daß ich nun meine Codebeispiele im Blog gerne mit Syntax-Highlighting ausstatten möchte. Manuell war das natürlich nicht zu machen. Bei der Suche nach etwas automatischen bin ich auf Coderay gestoßen. Damit sieht der Code schon mal viel ansprechender aus.

Hier mal ein Beispiel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require 'rubygems'
require_gem 'activerecord'

ActiveRecord::Base.establish_connection(
  :adapter    => "postgresql",
  :host       => "localhost",
  :database   => "artikel",
  :username   => "dbuser",
  :password   => "kryptisches_passwort"
)

class Selection < ActiveRecord::Base
  set_table_name "selections"
  set_primary_key "id"
  has_many  :items, 
            :class_name => "SelectionItem",
            :foreign_key => "selection_id",
            :order => "sort_order"
end

class SelectionItem < ActiveRecord::Base
  set_table_name "selectionitems"
  set_primary_key "id"
  belongs_to  :selection,
              :class_name => "Selection",
              :foreign_key => "selection_id"
end

Schick, oder?

Einfacher Prompt in der IRB

Der normale Prompt in der irb kann ein wenig verwirrend und Platzraubend sein. Wenn man auf die Informationen aus dem Prompt keinen großen Wert legt, kann man ihn ein wenig vereinfachen.

Die folgende Zeile in der ~/.irbrc macht den Prompt schön schlank.

IRB.conf[:PROMPT_MODE] = :SIMPLE

ActiveRecord ohne Rails

ActiveRecord ist einer der Gründe, wieso Ruby on Rails so einfach und flexibel ist. Es ist ein sogenannter objektrelationaler Mapper. Damit lassen sich Daten aus einer Datenbank wie Objekte behandeln. Aber auch ohne Rails läßt sich ActiveRecord recht einfach einsetzen.

Als Beispiel habe ich hier 2 Tabellen in PostgreSQL, in denen ich eine Auswahl an Artikeln speichern möchte. Die Tabelle selections enthält den Namen der Auswahl von Artikeln und in selectionitems befinden sich die Artikel aus Auswahllisten. Die Tabellen haben folgendes Schema:

CREATE TABLE selections (
  id                SERIAL PRIMARY KEY,
  name              VARCHAR(30)
);

CREATE TABLE selectionitems (
  id                SERIAL PRIMARY KEY,
  part_id           INTEGER,
  selection_id      INTEGER,
  sort_order        INTEGER
);

Die beiden Tabellen habe ich mit Testdaten gefüllt.

artikel=# select * from selections;
 id | name
----+------
  1 | foo
(1 row)

artikel=# select * from selectionitems;
 id | part_id | selection_id | sort_order
----+---------+--------------+------------
  1 |      23 |            1 |          3
  2 |      42 |            1 |          1
  3 |     123 |            1 |          2
(3 rows)

Die Namen der Tabellen und der Felder sind schon ziemlich Rails-like, so daß in den folgenden Beispielen sehr viele Einstellungen überflüssig sind. Aber ich habe sie hier eingetragen, um zu zeigen, wie man mit beliebigen Tabellen arbeiten könnte.

Mit ActiveRecord verpacke ich nun die beiden Tabellen. Falls es beim require bzw. require_gem zu Fehlern kommen sollte, sind vermutlich die Ruby Gems bzw. das ActiveRecord-Gem nicht installiert. (Genaueres ist auf der Ruby Gems Website beschrieben)

require 'rubygems'
require_gem 'activerecord'

ActiveRecord::Base.establish_connection(
  :adapter    => "postgresql",
  :host       => "localhost",
  :database   => "artikel",
  :username   => "dbuser",
  :password   => "kryptisches_passwort"
)

class Selection < ActiveRecord::Base
  set_table_name "selections"
  set_primary_key "id"
  has_many  :items,
            :class_name => "SelectionItem",
            :foreign_key => "selection_id",
            :order => "sort_order"
end

class SelectionItem < ActiveRecord::Base
  set_table_name "selectionitems"
  set_primary_key "id"
  belongs_to  :selection,
              :class_name => "Selection",
              :foreign_key => "selection_id"
end

Das war der ganze Code, um die beiden Tabellen in Objekte zu verpacken. Was genau steht nun da oben? ActiveRecord::Base.establish_connection() dürfte eigentlich selbsterklärend sein. Interessant wird es bei der Klasse Selections. Ich sage der Klasse mit set_table_name auf welcher Tabelle aus der Datenbank sie basieren soll und mit set_primary_key wie die Spalte mit dem Primärschlüssel heißt. (ActiveRecord hat hier einige Automatismen um vom Namen der Klasse auf den Tabellennamen zu schließen, die ich jedoch bewußt nicht benutzt habe.) Mit has_many habe ich bestimmt, daß jede Instanz der Klasse Selections mehrere Instanzen der Klasse SelectionItem enthalten kann. Die Zuordnung dieser items zu einer Selection geschieht anhand der selection_id aus SelectionItem. Ähnlich habe ich auch in SelectionItem bestimmt, auf welcher Tabelle es basieren soll. Und umgekehrt zu has_many habe ich hier mit belongs_to festgelegt, daß eine Instanz von SelectionItem zu einer bestimmten Selection gehört.

Wie benutze ich das nun? Ich ich suche erstmal die in den Tabellen gespeicherte Auswahl.

irb(main):028:0> foo = Selection.find_by_name("foo")
=> #"foo", "id"=>"1"}>

Wer Ruby on Rails schon gesehen hat, wird das wiedererkennen. Und all die anderen halten es für Magie :) Hier ist die erste Auswahl mit den Namen foo. Diese Auswahl enthält nun einige Artikel. Mal schauen, was ich da habe.

irb(main):029:0> foo.items.count
=> 3
irb(main):030:0> foo.items.each { |bar| puts bar.part_id }
42
123
23

Da ist meine Auswahl. Jetzt will ich ein weiteren Artikel zu dieser Auswahl hinzufügen.

irb(main):031:0> foo.items.create(:part_id => 451, :sort_order => 4)
=> #>, @attributes={"part_id"=>451, "sort_order"=>4, "selection_id"=>1, "id"=>4}>
irb(main):032:0> foo.items.count
=> 4
irb(main):033:0> foo.items.each { |bar| puts bar.part_id }
42
123
23
451

Das war aber noch nicht alles. Ich möchte in meiner Auswahl den zweiten Artikel herausfinden.

irb(main):035:0> foo.items.find_by_sort_order(2).part_id
=> 123

Ich kann diese Auswahl aber auch wie ein Array betrachten. (Achtung, Arrays fangen bei 0 an!)

irb(main):038:0> foo.items[1].part_id
=> 123

Besondere Erwähnung verdient die Suchfunktion. Ich sage nur find_by_feldname, und es wird anhand dieses Feldes in der Tabelle gesucht. ActiveRecord erzeugt also automagisch für alle Tabellenfelder find-Methoden. Das geht sogar so weit, daß man auch mehrere Suchkriterien kombinieren kann.

irb(main):041:0> foo.items.find_by_part_id_and_sort_order(123,2)
=> #"123", "sort_order"=>"2", "selection_id"=>"1", "id"=>"3"}>

Wenn ActiveRecord nichts findet, gibt es einfach nil zurück.

irb(main):040:0> foo.items.find_by_part_id_and_sort_order(123,3)
=> nil

Und für all diejenigen, die ihren Augen noch nicht trauen, hier noch ein letzter Blick in die Datenbank. Ich zeige hier nur die Tabelle selectionitems, da ich nur darin was geändert habe.

artikel=# select * from selectionitems;
 id | part_id | selection_id | sort_order
----+---------+--------------+------------
  1 |      23 |            1 |          3
  2 |      42 |            1 |          1
  3 |     123 |            1 |          2
  4 |     451 |            1 |          4
(4 rows)

Wer sich nun mit den Details von ActiveRecord auseinander setzen möchte, sollte in die Ruby on Rails-Dokumentation schauen.

Ruby 1.8.5

Noch steht es nicht auf der Ruby-Website, doch gerade eben hat Matz die Version 1.8.5 von Ruby veröffentlicht.

Nachtrag 17:40Uhr: Wie ich gerade lese, hat die Ruby-Website auch noch ein 2.0mäßiges Facelifting bekommen. Leider kann ich es gerade nicht bewundern, daß es auch gleich auf Digg geposted wurde, wodurch die Website nun gar nicht mehr erreichbar ist. Zum Glück konnte ich mir den Source ziehen, als die Website ihr altes Design noch hatte :)

Zahlen formatieren in Ruby

Es muß nicht immer printf sein, um Zahlen in Ruby zu formatieren. Ruby kennt da einen eleganteren Weg.

irb(main):001:0> foo=3.14159265358979323846264338328
=> 3.14159265358979
irb(main):002:0> "%.4f"%foo
=> "3.1416"

Zwar muß man immer noch die relativ umständlichen Printf-Style Format-Strings angeben, doch muß man sich nicht mit den Platzhaltern in den Strings herumschlagen.

Programmieren lernen für Nicht-Geeks

Ich höre oft von meinen Nicht-Geek Freunden, daß sie gerne ein wenig programmieren lernen würden, wäre es nicht so komplex. Was sie natürlich meinen ist, daß Programmcode in vielen Programmiersprachen geradezu kryptisch aussieht. Ich habe meinen Freunden immer empfohlen, sich Ruby anzuschauen. Doch Bücher wie Programming Ruby sind eher an Leute gerichtet, die zumindest das Konzept des Programmierens verinnerlicht haben. Ich habe bislang den Nicht-Geeks das Poignant Guide to Ruby empfohlen. Nun sieht es so aus, als wäre ein Buch erschienen, das sich genau an diese Leute richtet. Learn to Program ist wohl genau das richtige Buch, um nicht nur eine Programmiersprache (Ruby) zu lernen sondern auch ein wenig die Denkweise eines Programmierers nahezubringen. Die auf der Website verfügbaren Abschnitte des Buches sehen jedenfalls sehr vielversprechend aus. Ich werde das Buch mal weiterempfehlen.