Ruby array sort and uniq bug

Ruby — Dillon @ 5:45 pm

I found a ruby bug, reported it and it got fixed. I’m posting this because I thought the whole process was pretty cool. I very rarely find bugs but it’s always fun feeling like you’re giving back to the community you’ve lurked in for a long time.

First, the bug.

a = [
  { :color => "blue",  :name => "water" },
  { :color => "red",   :name => "fire" },
  { :color => "white", :name => "wind" },
  { :color => "green", :name => "earth" },
  { :color => "green", :name => "moss" },
  { :color => "white", :name => "snow" }
]
 
# taking out the sort_by solves the problem
a.sort_by! { |e| e[:color] }
a.uniq! {|e| e[:color]}
 
puts a

Now it’s supposed to print this:

{:color=>"blue", :name=>"water"}
{:color=>"green", :name=>"moss"}
{:color=>"red", :name=>"fire"}
{:color=>"white", :name=>"wind"}

But instead ruby crashes. On OSX, it’s a BAD_EXEC error. On Linux, it drops core with another error. You can read my whole bug report here. I wanted to test it a bunch and I found that the sort_by! is what causes it. There were many workarounds possible but ruby should handle this case.

Anyway, I submitted a bug on the redmine site. I knew redmine from work so this was easy. Some time later, Yui Naruse committed a fix. Now, I had attempted to trace the issue myself. But it’s all C and ruby is huge. So I was completely lost. I can’t even tell what the solution actually is even when looking at it. :(

So the issue was closed, revision 30739 had the fix. So I tried to update ruby-1.9.2-head using RVM but it kept pulling an older version. I tried doing rvm cleanup all 1.9.2-head but it kept pulling and building an older revision. So I just checked out ruby from SVN and built it:

cd ~/tmp
svn co http://svn.ruby-lang.org/repos/ruby/trunk ruby
mv ruby/ ruby_svn_30739
cd ruby_svn_30739/
autoconf ./configure.in > configure
chmod u+x ./configure
./configure
make

This was on a mac, so you have to have autoconf (I think I’m using the homebrew version). Anyway, ruby is built but I didn’t want to install it if I couldn’t built it with RVM (because it’d be hard to tear it out — or at least I didn’t know how). So I was able to run the built ruby without installing like this:

user@box:ruby_svn_30739$ ./ruby -I lib:. bug.rb

Where bug.rb is the code from above that crashes ruby. And when you run it, it prints out the hash after removing the uniques based on a hash key.

Pretty awesome day today. And I can always check if it’s in the Ruby interpreter by doing this:

 wget --no-check-certificate -O - https://github.com/ruby/ruby/raw/trunk/array.c \
| grep -A 4 ARY_SHARED_P |grep -B 4 ary_resize

Grep will return this.

if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
  rb_ary_unshare(ary);
  FL_SET_EMBED(ary);
}
ary_resize_capa(ary, i);

Of course the better way is to run the included ruby tests that Yui Naruse wrote. :)

Setting the default ruby with Pik

Ruby — Dillon @ 10:08 pm

Pik is a nice alternative to RVM if you’re on Windows. RVM has a few more features than pik but all in all, pik does exactly what I want with very similar commands as RVM so it was a really nice transition. I’m extremely impressed that they could get the whole thing to work actually.

However, there were a few gotchas (all detailed below).

  1. You need some version of ruby installed to get pik up and running.
  2. After installing any ruby using pik, you can switch your default and uninstall the bootstrap version if you wish.
  3. Pik supports proxies using the http_proxy environment variable.
  4. Installing a specific version has slightly different syntax than RVM.

First, you need some version of ruby installed (#1 up there). I used JRuby for Windows (jruby_windows_x64_1_6_0_RC1.exe — ymmv) because it had no dependencies. JRuby gets installed to C:\jruby-1.6.0.RC1 (ymmv based on version) and pik picks it up and adds it to its list (very nice). If you don’t have a version of ruby installed you’ll get:
error: can't dup nilclass
when you try to run pik.

What’s really nice is that jruby’s binary is jruby and not ruby. But pik handled it. I just ran both installers and then I had jruby in my “pik list”.

What do I mean by pik list? It’s just like RVM.
C:\Users\you>pik list
160: jruby 1.6.0.RC1 (ruby 1.8.7 patchlevel 330) (2011-01-10 769f847) (Ja...
187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mingw32]
* 192: ruby 1.9.2p136 (2010-12-25) [i386-mingw32]

Second, I wanted to set the default ruby with pik (why you are here reading this). This was a bit odd and different than RVM. RVM loads in the .bashrc so it makes sense that pik can’t override the Windows cmd lifecycle. The PATH variable sets which ruby is the default. So just go to your Windows System Properties and set your user’s %PATH% variable to the bin path of whichever ruby you want to use. You can get the path like this:

C:\Users\you>pik list -v
160: jruby 1.6.0.RC1 (ruby 1.8.7 patchlevel 330) (2011-01-10 769f847) (Ja...
...va HotSpot(TM) 64-Bit Server VM 1.6.0_22) [Windows 7-amd64-java]
path: C:\jruby-1.6.0.RC1\bin

187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mingw32]
path: C:\Users\you\.pik\rubies\Ruby-187-p330\bin

* 192: ruby 1.9.2p136 (2010-12-25) [i386-mingw32]
path: C:\Users\you\.pik\rubies\Ruby-192-p136\bin

So for example, if you wanted 1.9.2 to be your default ruby, just add C:\Users\you\.pik\rubies\Ruby-192-p136\bin to the beginning of your user defined %PATH% variable in System Properties. When you fire another cmd.exe, ruby should be all set. Apparently this is the equivalent of the rvm use 1.9.2 --default on a ‘nix system.

Pik supports proxies (phew). Just do:
set http_proxy=http://yourproxy

You can test with viewing all the remote rubies:
pik list -r

Also, add this environment variable to your user’s variable list just like you did with the %PATH% variable.

Installing a specific version is a bit different than RVM, you specify the version with a space. In RVM, this would be “rvm install ruby-1.9.2″
pik install ruby 1.9.2-rc1

Update:
If you want to install a new ruby and move your gems do this:
pik install ruby 1.9.2-p180
pik use 1.9.2-p180
(set your %PATH% to default as described above if you want)
pik gemsync p136 (imports from p136 into current which is p180)

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2012 SQUARISM | powered by WordPress with Barecity