/usr/local/lib/ruby/gems/1.8/gems/activesupport-2.3.3/lib/active_support/multibyte/unicode_database.rb:37: [BUG] Segmentation fault ruby 1.8.7 (2010-01-10 patchlevel 249) [powerpc-darwin8.11.0]As described in the ticket the error occurs only in patchlevel 248 and 249. So I had to go back to p174 and now everything runs smoothly again.
Posts mit dem Label Ruby werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Ruby werden angezeigt. Alle Posts anzeigen
Samstag, 20. Februar 2010
Avoid Ruby 1.8.7 p248 and p249 with ActiveSupport
Yesterday I updated the stage environment of Zero X to ruby 1.8.7, but after that I suddenly couldn't login anymore. The problem was a Segmentation fault in Marshal.load used by ActiveSupport:
Sonntag, 7. Februar 2010
Codename Zero X
Zero X is a new programming game, written in ruby and made to write in ruby. The first level is based on the greenfield scenario described in an early (german) post.
The players can code agents, which then will be uploaded to participate to the tournaments.
I hope to release a first beta version still this month, until then I leave you with a first screenshot showing the ranking page:
The players can code agents, which then will be uploaded to participate to the tournaments.
I hope to release a first beta version still this month, until then I leave you with a first screenshot showing the ranking page:
Labels:
programming game,
Ruby,
scenario greenfields,
zero x
Donnerstag, 24. September 2009
Migration auf Ruby 1.9.1
In den letzten Tagen habe ich mein Simulation Projekt auf Ruby 1.9 migriert. Leider verlief die Migration nicht ganz so einfach, wie ich mir das vorgestellt hatte. Teilweise muss nämlich eine exakte Version eines Gems installiert werden, ansonsten hagelt es Fehlermeldungen.
Um Ruby 1.8 und 1.9 parallel auf meinem Mac betreiben zu können, habe ich RVM installiert. Dies installiert alle zusätzlichen Ruby Versionen im Home-Verzeichnis unter .rvm. Zudem werden auch alle command line Befehle wie etwa 'rails' oder 'cucumber' separat gehandhabt. Unter RVM ist allerdings zu beachten, dass alle so hinzugefügten Gems nicht mit sudo installiert werden. Zudem musste ich eine frühere Version von Ruby 1.9, die ich noch unter /usr/local hatte, zuerst wegputzen.
Ich will hier nicht alle Leerläufe beschreiben, deshalb hier gleich die hoffentlich richtig Anleitung:
Um auf Ruby 1.9 zu wechseln:
Danach wenden wir uns gleich Rails selber zu. Die neuste Version 2.3.4 ist leider nicht lauffähig unter Ruby 1.9. Wenn auf die Session zugegriffen wird, erhaltet man folgenden Fehler:
Um Ruby 1.8 und 1.9 parallel auf meinem Mac betreiben zu können, habe ich RVM installiert. Dies installiert alle zusätzlichen Ruby Versionen im Home-Verzeichnis unter .rvm. Zudem werden auch alle command line Befehle wie etwa 'rails' oder 'cucumber' separat gehandhabt. Unter RVM ist allerdings zu beachten, dass alle so hinzugefügten Gems nicht mit sudo installiert werden. Zudem musste ich eine frühere Version von Ruby 1.9, die ich noch unter /usr/local hatte, zuerst wegputzen.
Ich will hier nicht alle Leerläufe beschreiben, deshalb hier gleich die hoffentlich richtig Anleitung:
Um auf Ruby 1.9 zu wechseln:
rvm install 1.9 rvm use ruby 1.9Darauf installiert RVM automatisch die aktuelle 1.9 Version.
Danach wenden wir uns gleich Rails selber zu. Die neuste Version 2.3.4 ist leider nicht lauffähig unter Ruby 1.9. Wenn auf die Session zugegriffen wird, erhaltet man folgenden Fehler:
undefined method `^' for "c":String (NoMethodError)Deshalb muss auf 2.3.3 zurückgegriffen werden:
gem install -v='2.3.3' railsMein Projekt nutzt Cucumber und RSpec als Testframeworks. Hier können zwar die neusten Versionen installiert werden, jedoch muss auch Test-Unit mit der Version 1.2.3 und zwar exakt diese mitinstalliert werden:
gem install cucumber rspec rspec-rails webrat gem install -v="1.2.3" test-unitAls nächstes meldete Nokogiri, das von Webrat genutzt wird, einen Konflikt:
dyld: lazy symbol binding failed: Symbol not found: _rb_intern2 Referenced from: /Users/adm/.rvm/gems/ruby/1.9.1/gems/nokogiri-1.3.3/lib/nokogiri/nokogiri.bundle Expected in: flat namespace dyld: Symbol not found: _rb_intern2 Referenced from: /Users/adm/.rvm/gems/ruby/1.9.1/gems/nokogiri-1.3.3/lib/nokogiri/nokogiri.bundle Expected in: flat namespace Trace/BPT trapUm diesen Konflikt zu lösen musste ich über Ports meine libxml Bibliothek aktualisieren und Nokogiri nochmals installieren:
sudo port install libxml2 sudo port install libxslt gem install nokogiriDanach startete mein Projekt endlich unter Ruby 1.9 auf. Meine eignen Konflikte mit 1.9 konnte ich dank meinen Testsuits innerhalb einer halben Stunde lösen. Gute Tests sind wirklich Gold wert.
Mittwoch, 26. August 2009
Nested Synchronize Blocks
In my new simulation project I have different threads accessing objects. The simulation server calculates periodically their states and the tournament server, handling all agents, is accessing them over distributed Ruby. Therefore I need to synchronize the sim objects. My first attempt looked something like this:
But I needed a different behaviour, I want to synchronize the objects from different threads. As far as I remember Java's synchronize behaves the same way.
Using rspec we could specify this behaviour with 2 tests:
For the second test we need two different threads. The first thread locks the object and lunches a second thread. The first one returns immediately after fork, while the second one is launched in the meantime. So while the first is waiting for a second, the second thread is trying to achieve the lock and is blocked until the first one releases it on line 12. Only now the second thread gets access to the object and can set wait_for_me to false.
Of course both tests fail (or get some deadlocks) with the implemention above. The second version of synchronize looks now like this:
class SyncObject
def initialize
@semaphore = Mutex.new
end
def synchronize &block
@semaphore.synchronize &block
end
end
Before changing something in the sim objects, I synchronize them :
object.synchronize do
# change the state of the object
end
But as things were growing, I suddently got some deadlocks. After some research I found out, that a thread was invoking synchronize on the same object multiple times. The semaphore object doesn't care which thread is locking it. As long it's locked it will block all threads until the block is finished. Even if it's the same thread, that locked the semaphore just before.
But I needed a different behaviour, I want to synchronize the objects from different threads. As far as I remember Java's synchronize behaves the same way.
Using rspec we could specify this behaviour with 2 tests:
it "should not block the same thread when synchronizing" do
object = SyncObject.new
object.synchronize do
object.synchronize do
object.synchronize do
true.should be_true
end
end
end
end
it "should block two different threads when synchronizing" do
object = SyncObject.new
wait_for_me = true
object.synchronize do
Thread.fork do
object.synchronize do
wait_for_me = false
end
end
sleep 1
wait_for_me.should be_true
end
wait_for_me.should be_false
end
The first test's pretty straight forward, we want to allow nested synchronize blocks for the same thread.For the second test we need two different threads. The first thread locks the object and lunches a second thread. The first one returns immediately after fork, while the second one is launched in the meantime. So while the first is waiting for a second, the second thread is trying to achieve the lock and is blocked until the first one releases it on line 12. Only now the second thread gets access to the object and can set wait_for_me to false.
Of course both tests fail (or get some deadlocks) with the implemention above. The second version of synchronize looks now like this:
class SyncObject
def initialize
@semaphore = Mutex.new
end
def synchronize
unless @current_thread == Thread.current
@semaphore.synchronize do
@current_thread = Thread.current
yield
@current_thread = nil
end
else
yield
end
end
end
The first time synchronize is accessed, @current_thread is set to the current running thread. The semaphore is locked and the blocked yield. If in the meantime a different thread invokes synchronize, it will be blocked until the first one finishes the block. Else if the same thread access the method in the meantime, it will not try to lock the semaphore again, but can yield its new block immediately.
Labels:
Concurrency,
Java,
Ruby
Mittwoch, 5. August 2009
Closures in Distributed Ruby
In this article I want to show how closures work with distributed ruby and what you have to do to make them work.
Here's a very simple server to start:
Now let's add a method that uses a block parameter.
in the server:
All we have to do to make it work is starting also a drb service on the client side.
Here's a very simple server to start:
require 'drb'
class SimpleServer
def initialize
DRb.start_service('druby://localhost:9000', self)
end
def server_time
Time.now
end
end
SimpleServer.new
DRb.thread.join
In the constructor we start the drb service and register the server to localhost on port 9000. Then we have a very simple method, which just returns the time on the server, that we now want to call from our client. The last line prevents the programm to exit and keeps the server thread waiting for incoming requests.
require 'drb'
class SimpleClient
def initialize
@remote = DRbObject.new(nil, 'druby://localhost:9000')
end
def time_on_server
puts "Time on server #{@remote.server_time}"
end
end
client = SimpleClient.new
client.time_on_server
In the client's constructor we get the remote object of the previous registered server. After that we can call the "time_on_server" method to print it on the client side.
Now let's add a method that uses a block parameter.
in the server:
def time_on_client
puts "Time on client #{yield}"
end
and in the client:
def client_time
@remote.time_on_client { Time.now }
end
Calling now "client_time" from the client, will raise a DRb::DRbServerNotFound error. The client fails to provide a drb proxy object for the server, which would need it to call the block on the client again. Blocks are bind to the environment, where they have been defined, in our case on the client.
All we have to do to make it work is starting also a drb service on the client side.
def initialize
DRb.start_service
@remote = DRbObject.new(nil, 'druby://localhost:9000')
end
So in Ruby we often have symetric roles, both sides need to act as client and server.
Labels:
Distributed Ruby,
drb,
Ruby
Sonntag, 5. April 2009
Reading Binary Files with Ruby
For my current project I need to read some binary data with Ruby. The data file is formatted as 16-bit BINARY INTEGERS, hi-byte-first order with 2160 x 4320 data values.
From my Java days I knew the DataInputStream class. With it it's every easy to read the data, just use io.readShort().
Therefore I was looking everywhere in IO and File for some methods to read the data in an appropriate format. But I couldn't find anything really useful as all methods are working with strings and characters.
But then I found the pack method in Array and its corresponding method unpack in String. With this two methods it's easy to read and write binary files in various formats.
Here the code snippet where I read the gzip compressed file. @size is in my case 4320 and @height an array of 2160. After reading the file I can access the data with @data[line][row].
From my Java days I knew the DataInputStream class. With it it's every easy to read the data, just use io.readShort().
Therefore I was looking everywhere in IO and File for some methods to read the data in an appropriate format. But I couldn't find anything really useful as all methods are working with strings and characters.
But then I found the pack method in Array and its corresponding method unpack in String. With this two methods it's easy to read and write binary files in various formats.
Here the code snippet where I read the gzip compressed file. @size is in my case 4320 and @height an array of 2160. After reading the file I can access the data with @data[line][row].
Zlib::GzipReader.open(filename) do |gz|
x = 0
# read one line (16-Bit-Integer = 2 bytes)
while line = gz.read(2 * @size)
@data[x] = line.unpack('s' * @size)
x += 1
end
end
If you need more, have a look at BitStruct. It provides a nice DSL for handling binaries.
Donnerstag, 26. Februar 2009
Using multiple Ruby versions with Textmate
I have currently Ruby 1.8.6 and 1.9.1 on my machine. To test my libraries against both versions, it would be very convenient to switch between versions within your IDE . With Netbeans there's no problem as you can define different ruby environments (Tools/Ruby Platforms). In Textmate I couldn't find anything like that. But there's an easy way too: just define the path to your ruby version in the start script, just like you would do it for a shell script.
#!/usr/bin/ruby puts RUBY_VERSION # => 1.8.6
#!/usr/local/bin/ruby1.9 puts RUBY_VERSION # => 1.9.1
Sonntag, 4. Januar 2009
Implementing if in Ruby the Smalltalk Way
In Smalltalk the if statement is not a keyword, but also a normal message sending to an object. In this case the object receiving the message is a boolean. When a condition is resolved it is either true or false and therefore we can send the messages ifTrue and ifFalse to it.
This can easly be implemented in Ruby by patching the corresponding True- and FalseClass:
condition ifTrue: [ doSomething ] ifFalse: [ doSomethingElse ]If the condition is true the first block will be executed, if false the second block will executed.
This can easly be implemented in Ruby by patching the corresponding True- and FalseClass:
class TrueClass
def if_true
yield
self
end
def if_false
self
end
alias if if_true
alias else if_false
end
class FalseClass
def if_true
self
end
def if_false
yield
self
end
alias if if_true
alias else if_false
end
As you can see I always return self, so that we chain the methods.
Now we can write:
i = 5
(i > 3).if_true {puts 'true'}.if_false {puts 'false'}
Using the alias methods we can write it in the more common form:
i = 5
(i > 3).if {puts 'true'}.else {puts 'false'}
or
i = 5 (i > 3).if do puts 'true' end.else do puts 'false' end
Dienstag, 4. November 2008
Compiling Ruby 1.9.1 on Leopard
Update
With the new Ruby 1.9.1 stable version, I only used the following configure (--with-readline-dir is not recognized anymore)
The new Ruby 1.9 Preview is out, time for a first impression. But already step one, compiling readline 5.2 failed. Thanx to Han's Hint, I was able to patch the responsible shobj-conf file.
So after patching readline's conf file, in the readline-5.2 directory:
With the new Ruby 1.9.1 stable version, I only used the following configure (--with-readline-dir is not recognized anymore)
./configure --prefix=/usr/local --program-suffix=1.9 make sudo make install
The new Ruby 1.9 Preview is out, time for a first impression. But already step one, compiling readline 5.2 failed. Thanx to Han's Hint, I was able to patch the responsible shobj-conf file.
So after patching readline's conf file, in the readline-5.2 directory:
./configure --prefix=/usr/local make sudo make installNow compiling ruby should work as expected, don't forget to point to your new compilied readline library. In your ruby directory:
./configure --prefix=/usr/local --program-suffix=1.9 --with-readline-dir=/usr/local make sudo make installNow you have both ruby versions in parallel, try ruby -v and ruby1.9 -v
Dienstag, 3. Juni 2008
Ruby meets Smalltalk
Avi Bryant , der Autor des Smalltalk Webframework Seaside, hat dieses Wochenende an der RailsConf 2008 MagLev vorgestellt, eine VirtualMachine für Ruby. Gemstone, die Firma hinter MagLev, hat schon jahrzentelange Erfahrung mit Smalltalk VMs und hat dieses Knowhow nun für Ruby umgemünzt. Anders ist auch kaum zu erklären wie sie in so kurzer Zeit, die Rede ist von 3 Monaten, eine eigene VM auf die Beine stellen konnten.
Erste Demos und Vergleiche mit MRI scheinen den alten Intepreter schlicht und einfach stehen zu lassen, MagLev soll je nach Benchmarktest zwischen 6 und 111 mal schneller sein.
Allzu oft haben wir schon gehört, dass eigentlich nichts dagegenspricht, dass Ruby so schnell wie Smalltalk sein könnte. MagLev hat nun offenbar den Beweis angetreten.
Noch ist MagLev nicht fähig Rails laufen zu lassen, aber Avi Bryant scheint keine Zweifel daran zu haben, dass auch dies in Kürze erreicht werden kann.
Die Kehrseite an der neuen VM ist wohl, dass sie nicht OpenSource sein wird. Der Ruby Sourcecode wird zwar öffentlich sein, der C Code für den Compiler wird aber geschlossen bleiben. Voraussichtlich wird es verschiedene Lizenzen je nach Grösse und Umfang geben. Ist zu hoffen, dass MagLev auch in einer Version für kleinere Budgets zu haben ist. Denn viel wird genau davon abhängen, ob sich MagLev in der Rails Community durchsetzten kann.
Update: Der erste Teil von Avi's Präsentation:
MagLev presentation at RailsConf 2008 - part 1 from Monty Williams on Vimeo.
Erste Demos und Vergleiche mit MRI scheinen den alten Intepreter schlicht und einfach stehen zu lassen, MagLev soll je nach Benchmarktest zwischen 6 und 111 mal schneller sein.
Allzu oft haben wir schon gehört, dass eigentlich nichts dagegenspricht, dass Ruby so schnell wie Smalltalk sein könnte. MagLev hat nun offenbar den Beweis angetreten.
Noch ist MagLev nicht fähig Rails laufen zu lassen, aber Avi Bryant scheint keine Zweifel daran zu haben, dass auch dies in Kürze erreicht werden kann.
Die Kehrseite an der neuen VM ist wohl, dass sie nicht OpenSource sein wird. Der Ruby Sourcecode wird zwar öffentlich sein, der C Code für den Compiler wird aber geschlossen bleiben. Voraussichtlich wird es verschiedene Lizenzen je nach Grösse und Umfang geben. Ist zu hoffen, dass MagLev auch in einer Version für kleinere Budgets zu haben ist. Denn viel wird genau davon abhängen, ob sich MagLev in der Rails Community durchsetzten kann.
Update: Der erste Teil von Avi's Präsentation:
MagLev presentation at RailsConf 2008 - part 1 from Monty Williams on Vimeo.
Labels:
MagLev,
Performance,
Ruby,
Smalltalk
Mittwoch, 19. März 2008
Ruby People
Für den zweiten Teil meiner Präsentation habe ich mich auf die Suche nach einigen bekannten Köpfen in der Ruby Gemeinschaft gemacht. Dabei war ich doch etwas zu eifrig, so dass meine Folie bald überladen war und ich sie aus der Präsentation kippen musste. Stattdessen stelle ich das "Gruppenbild" hier auf den Blog:
Donnerstag, 28. Februar 2008
By reference oder doch by value?!
Bei der Vorbereitung einer Schulung für Ruby bin ich auf eine verwirrende Eigenschaft gestossen:
Objekte werden in Ruby immer by reference übergeben, da Variablen nichts anderes als Referenzen auf Objekte sind. Aber siehe da:
Sieht aber so aus als ob Ruby nicht per reference übergeben würde, sondern by value.
Doch ein Blick in Docu zeigt, dass die Methode '+' ein neues Objekt mit dem Wert 2 zurückgibt, auf das nun n zeigt. Während i immer noch auf das alte Objekt mit dem Wert 1 zeigt. Würde Ruby kein neues Objekt erzeugen, sondern den Methoden-Receiver tatsächlich ändern:
ja dann wäre nach dieser Operation nicht nur c = 3, sondern auch a = 3.
Das ist aber immer noch nicht die ganze Wahrheit. Auch im folgendem Beispiel scheint Ruby by value zu übergeben:
Auch hier zeigt x nach dem Aufruf zwar auf 2, aber a immer noch auf 1. Doch die eigentliche Frage ist, warum werden überhaupt zwei Referenzen gebildet?
Weil Ruby Referenzen by value übergibt!
Übrigens herrscht in der Java-Welt immer noch das Gerücht, dass primitive Types by value übergeben werden und Objekte by reference. Stattdessen verhält sich Java genau gleich.
Objekte werden in Ruby immer by reference übergeben, da Variablen nichts anderes als Referenzen auf Objekte sind. Aber siehe da:
def inc(n) n = n + 1 end i = 1 inc(i) # => 2 puts i # => 1
Sieht aber so aus als ob Ruby nicht per reference übergeben würde, sondern by value.
Doch ein Blick in Docu zeigt, dass die Methode '+' ein neues Objekt mit dem Wert 2 zurückgibt, auf das nun n zeigt. Während i immer noch auf das alte Objekt mit dem Wert 1 zeigt. Würde Ruby kein neues Objekt erzeugen, sondern den Methoden-Receiver tatsächlich ändern:
a = 1 b = 2 c = a + b
ja dann wäre nach dieser Operation nicht nur c = 3, sondern auch a = 3.
Das ist aber immer noch nicht die ganze Wahrheit. Auch im folgendem Beispiel scheint Ruby by value zu übergeben:
def swap x,y y, x = x, y end a = 1 b = 2 swap a, b puts a # => 1 puts b # => 2
Auch hier zeigt x nach dem Aufruf zwar auf 2, aber a immer noch auf 1. Doch die eigentliche Frage ist, warum werden überhaupt zwei Referenzen gebildet?
Weil Ruby Referenzen by value übergibt!
Übrigens herrscht in der Java-Welt immer noch das Gerücht, dass primitive Types by value übergeben werden und Objekte by reference. Stattdessen verhält sich Java genau gleich.
Montag, 25. Februar 2008
Erster Blick auf Cassandra
Es wird Zeit Cassandra vorzustellen, ein Projekt, das im Januar 2008 seine erste Version 0.2 erreicht hat.
Cassandra ist der Versuch eine logische Programmiersprache zu gestalten, die in einer objekt-orientierten Umgebung anwendbar ist. Logische Programmiersprachen wie Prolog folgen der Prädikatenlogik, wodurch das Prädikat im Vordergrund steht:
In Cassandra soll nach wie vor, das Objekt im Vordergrund stehen, das Prädikat hat eine ähnliche Stellung wie Objektattribute:
Cassandra besteht ebenfalls wie Prolog aus Fakten, die mit einem Ausrufezeichen gekennzeichnet werden, Regeln und Abfragen (Queries), die mit einem Fragezeichen gekennzeichnet werden:
Cassandra wurde als DSL (Domain Specific Language) in Ruby implementiert. Symbole dienen hier als Variablen.
Cassandra kann bereits aus Regeln und Fakten logische Schlüsse ziehen, wie die oben erwähnten Beispiele zeigen. Der nächste Schritt besteht nun darin Datenstrukturen einzubinden und Vererbung zu ermöglichen.
Cassandra ist der Versuch eine logische Programmiersprache zu gestalten, die in einer objekt-orientierten Umgebung anwendbar ist. Logische Programmiersprachen wie Prolog folgen der Prädikatenlogik, wodurch das Prädikat im Vordergrund steht:
human(socrates). parents(child, father, mother).
In Cassandra soll nach wie vor, das Objekt im Vordergrund stehen, das Prädikat hat eine ähnliche Stellung wie Objektattribute:
socrates.human! child.parents!(father, mother)
Cassandra besteht ebenfalls wie Prolog aus Fakten, die mit einem Ausrufezeichen gekennzeichnet werden, Regeln und Abfragen (Queries), die mit einem Fragezeichen gekennzeichnet werden:
socrates.human? # => true :x.mortal!.if :x.human # => x = socrates
Cassandra wurde als DSL (Domain Specific Language) in Ruby implementiert. Symbole dienen hier als Variablen.
Cassandra kann bereits aus Regeln und Fakten logische Schlüsse ziehen, wie die oben erwähnten Beispiele zeigen. Der nächste Schritt besteht nun darin Datenstrukturen einzubinden und Vererbung zu ermöglichen.
Abonnieren
Posts (Atom)