ruby-mine

exploring the mine

-S: die Rettung vor dem Versionswahnsinn

von skade am 05.06.2009 (11 Uhr)

Jetzt hat mans fast geschafft: MRI 1.9, MRI 1.8 und JRuby sind parallel installiert und haben alle ihre eigene Executable. Alle benutzen verschiedene Gem-Repositories und die Installationen sind schön isoliert. Alles rosa? Fast! Es bleibt da noch das Problem mit ausführbaren gems...

Hat ein Gem Skripte im Verzeichnis bin, ist gem so intelligent und erstellt - sofern erlaubt - eine gleichnamige Datei im bin-Verzeichnis des Betriebssystems (bei *NIXen meist /usr/bin oder ähnliches). Dummerweise ist das dann global, wer also einen Gem 3 mal in verschiedenen Repositories installiert hat, bekommt am Ende doch nur einen Verweis. Die von Gem angelegte Executable sieht aber praktischerweise so aus und ist für alle gem-Versionen gleich:

#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'thin' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version = ">= 0"

if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
  version = $1
  ARGV.shift
end

gem 'thin', version
load 'thin'

Abgesehen davon, dass wir hier die wenig bekannte Möglichkeit sehen, eine Version zu forcieren (mit _1.2_ als Argument), fällt etwas anderes sofort ins Auge: die Executable verlässt sich komplett auf das von Rubygems angebotene lookup-System, um den Gem zu finden und dann die vom Gem angebotene Executable zu laden. So, wie kriegen wirs jetzt elegant hin, dem System zu erzählen, was er verwenden soll? Ein Blick in die Kommandozeilenparameter offenbart einen der besten Diebstähle bei Perl:

$ ruby --help
...
-S              look for the script using PATH environment variable
...

Praktisch! Das ist genau, was wir benötigen: die Möglichkeit, einen Interpreter anzugeben, der danach nochmal genau wie die Shell unter Verwendung von $PATH nach einer ausführbaren Datei sucht. Mit folgendem Kommando können wir als thin mit der ruby19-executable ausführen:

$ ruby19 -S thin ...

Darüber hinaus bietet uns das die Gelegenheit, robuste shellouts in Rakefiles zu machen, die sich nicht auf den Interpreternamen verlassen. Stattdessen soll immer der Interpreter verwendet werden, mit dem Rake ausgeführt wurde (die Konstante RUBY wird von Rake bereitgestellt):

task "start_thin" do
  system("#{RUBY} -S thin ... start")
end

Und wen das bei häufig verwendeten Programmen nervt, kann sich jetzt schnell mit einem Alias Abhilfe schaffen:

alias thin19="ruby19 -S thin"

Handlich ist der Parameter auch, wenn man den Trunk von Ruby verfolgt. Den habe ich meistens kompiliert, aber nicht installiert in src/ruby19 liegen. Problematischerweise sind die executables dann etwas anders sortiert und noch nicht mit Suffixen versehen, was zu folgendem Problem führt:

[ skade HIPE-Machine ~/src/ruby19 ] ./bin/irb
>> RUBY_VERSION
=> "1.8.6"

Args, IRB ist hier etwas intelligent und sucht per /usr/bin/env nach ruby. Also:

[ skade HIPE-Machine ~/src/ruby19 ] ./ruby -S bin/irb
>> RUBY_VERSION
=> "1.9.2"
irb(main):002:0> ->(a,b){}.parameters
=> [[:req, :a], [:req, :b]]

Damit bleibt mir eigentlich nur noch, euch viel -Spass mit Ruby zu wünschen ;).


Kommentar schreiben

Name (notwendig)

Mail (wird nicht veröffentlicht)

Webseite