Ruby-Programmierung: Rake

Zurück zum Inhaltsverzeichnis.

Im Unixumfeld ist das Programm Make weit verbreitet, um Aufgaben zu automatisieren, die mehrere Zwischenschritte erfordern. Dies kann zum Beispiel das Kompillieren eines Programmes sein oder das Updaten eines Servers.

Für Ruby gibt es das Programm Rake. Es ergänzt die Vorzüge von Make wie leichte Automatisierbarkeit von Abläufen und einfaches ansprechen über die Kommandozeile um die Programmiersprache Ruby. Ein Rakefile ist eine Rubyquelltextdatei.

today = Time.new

task :default => [:time]

desc "Printing the time"
task :time do
  puts today.to_s
end

Dieses Skript beschreibt einen einzigen task und definiert ihn als default. Dadurch kann er sowohl durch rake time als auch durch rake auf der Kommandozeile ausgeführt werden. In diesem Fall wird einfach die aktuelle Zeit auf der Kommandozeile angezeigt werden. Trotzdem dieses Beispiel nicht besonders umfangreich ist, kann man sich bei mehreren Tasks, die unterschiedliches bewirken sollen schnell Vorteile von Rake gegenüber einfachem Ruby vorstellen.

Rake erlaubt es außerdem Abhängigkeiten zwischen den Tasks zu definieren. Oben sieht man das schon, dass der Task default den Task time als Abhängigkeit besitzt, dadurch wird dieser Task ausgeführt bevor default ausgeführt wird. In diesem Fall wird also zuerst der Task time ausgeführt und zeigt die aktuelle Zeit an, danach wird default ausgeführt und tut nichts.

Besonders stark ist Rake bei der Transformation von Dateien, indem zum Beispiel Dateien aus anderen erzeugt werden. Dann lassen sich die Dateien als Abhängigkeiten der Zieldatei angeben und die Zieldatei wird nur dann neu erzeugt, wenn sich die Abhängigkeiten verändert haben.

Das folgende Skript fügt alle Dateien aus dem Unterordner src zusammen in einer Datei result:

files = FileList["src/**/*"]

task :default => "result"

file "result" => files do |t|
  content = files.map { |file| File.read(file) }.join("\n")
  puts "I'm writing the file"
  File.write(t.name, content)
end

Hier wurde an mehreren Stellen auf Rake zurückgegriffen, um die Arbeit zu erleichtern. Die FileList Klasse erlaubt das leichte zugreifen auf Dateien, die einem bestimmten Format entsprechen, in diesem Fall alle Dateien im Ordner src und dessen Unterordner, es ist auch möglich die Auswahl auf bestimmte Dateinamen einzuschränken.

Die Methode file erlaubt es wie task einen RakeTask zu erstellen. Im Gegensatz zu task das immer ausgeführt wird, wird file nur ausgeführt wenn die Abhängigkeiten sich geändert haben. Dadurch wird beim erstmaligen ausführen des Skriptes mit rake sowohl die Datei geschrieben, als auch die Zeile ausgegeben. Bei jedem weiteren Aufruf wird aber nichts mehr getan, außer eine der Dateien im Ordner src hat sich geändert. Dieses Verhalten ist insbesondere wünschenswert, wenn es sich um langsame Aufgaben handelt, so dass der langsame Teil nur bei Bedarf ausgeführt wird.

Automatisches Kompillieren

Bearbeiten

Dieses Rakefile wurde benutzt um im Kapitel über C-Erweiterungen die Erweiterungen automatisch zu kompillieren. Es müssen sich alle Dateien im Unterordner lib befinden.

Dir.chdir Dir.pwd + "/lib/"

FILES = []
Dir.open("./").each do |file|
  if file =~ /(.+)\.c$/
    FILES << $1
  end
end

task :default => [:compile]

desc "Compiling ..."
task :compile => [:extconf] do
  ruby "extconf.rb"
  system "make"
end

desc "Making extconf.rb ..."
task :extconf do
  file = File.open("extconf.rb", "w")
  file.puts "require 'mkmf'"
  FILES.each do |ext|
    file.puts "create_makefile '#{ ext }'"
  end
  file.close
end

desc "Cleaning everything ..."
task :clean do
  system "rm *.so *.o Makefile extconf.rb"
end