Pivotal Labs

Chad Woolley's blog



Evan Phoenix at Mountain West Ruby Conf

edit Posted by Chad Woolley on Monday March 31, 2008 at 05:20AM

I just attended (and thoroughly enjoyed) the Mountain West Ruby Conf, where Evan Phoenix gave a powerful keynote speech.

He talks about the status of Rubinius, and makes some profound observations on modern open source culture and community.

Here's some highlights, but if you participate in open source, and especially if you help run an open source project, I highly recommend that you watch the video:

  • Community: Rubinius' Giant Spec Suite, and its value not only as a living language specification for different implementations of Ruby itself, but as a "gateway drug" which provides a low barrier to get new contributors addicted to open source.
  • Trust: Asking for forgiveness vs. permission, and the Rubinius commit policy, where any accepted patch gets you commit rights. You can always roll back a change, and debate is healthy.
  • Worth: The impact of annoying fifteen year olds who make a lot noise versus "core" contributors.
  • Ego: You are not the project, Mr. Ego! The importance of being wrong and admitting your faults in public.
  • Innovation: Fostering innovation and debate vs closely holding the mythical "Keys to the Castle".

Removing Old Ruby Source Installation After a Leopard Upgrade

edit Posted by Chad Woolley on Friday February 22, 2008 at 02:38PM

Removing Ruby

I just upgraded to Leopard on my Mac. Previously, on Tiger, I had installed Ruby from source, in the default /usr/local/lib prefix. After reading the discussion on the Apple-provided Ruby installation, I decided to try it - mainly to ensure that my apps, such as GemInstaller, play well with it (on Pivotal's Mac pair workstations, we still install Ruby from source, so everything matches our demo/production environments as closely as possible, and things are in consistent locations).

So, I wanted to uninstall the old Ruby source installation, and only have the Apple-provided Ruby on disk. Googling for a few minutes did not provide exact instructions for this, so I'm writing up what I did, in hopes that it will help you!

I didn't use the "--prefix" option when I originally installed Ruby from source, so it was in the default location of /usr/local/lib/ruby, with binaries in /usr/local/bin.

WARNING: Use 'rm -rf' at your own risk - a sleep-deprived encounter with 'rm -rf' and a stray file named '~' is what "motivated" my Leopard upgrade in the first place...

First, I deleted the old ruby libraries/gems, which was easy enough, because they all lived under /usr/local/bin/ruby:

sudo rm -rf /usr/local/lib/ruby

However, this left all the old ruby/gems executables in /usr/local/bin. This resulted in errors when trying to run executable gems that I had not yet installed under the Apple Ruby installation:

$ cheat
/usr/local/bin/cheat:9:in `require': no such file to load -- rubygems (LoadError)
from /usr/local/bin/cheat:9

Instead of a cryptic rubygems error, I should get a 'file not found error':

$ sudo rm /usr/local/bin/cheat
$ cheat
-bash: /usr/local/bin/cheat: No such file or directory

So, I want to purge everything ruby-releated from my /usr/local/bin folder. I whipped up a quick ruby one-liner which just prints out (almost) all ruby-related files in /usr/local/bin:

ruby -e "old_ruby_execs = \`egrep 'rubygems|bin/ruby|env ruby' /usr/local/bin/*\`; require 'pp'; pp old_ruby_execs.split(\"\n\").collect{|line| line.split(':').first}.uniq"

Yeah, I know, ugly and obtuse, but one-liners are kind of fun, and help me remember that Ruby is great tool for sysadmin scripts. Feel free to put it in a class and test it if you are so inclined.

Even though I tried to make a fairly specific regexp for egrep, when inspecting that list, I did find a 'jgem' file, which was part of JRuby. I'm planning on reinstalling JRuby anyway, so I didn't care if that got deleted along with the other ruby stuff.

Anyway, if the output of that looks like everything you want to delete, then run this one-liner to do the actual deed (the 'sudo echo' is to 'prime' the sudo auth, so you don't get a noninteractive password prompt):

sudo echo; ruby -e "old_ruby_execs = \`egrep 'rubygems|bin/ruby|env ruby' /usr/local/bin/*\`; old_ruby_execs.split(\"\n\").collect{|line| line.split(':').first}.uniq.each { |exec| p 'removing ' + exec; \`sudo rm #{exec}\`}"

After that, the only thing that I saw left was the 'ruby' executable itself, which I whacked as well:

$ sudo rm /usr/local/bin/ruby

That seems to be about it, as least good enough to get all the old invalid executables off my path. I'm sure this could have been done cleaner if I had taken more care with the original source install. However, a good brute-force approach never hurt anyone. Much. Feel free to post links to relevant and helpful stuff.

Standup 01/18/2008

edit Posted by Chad Woolley on Friday January 18, 2008 at 05:46PM

Interesting Things

  • If you use Git, and have problems with gitk, try qgit. It may work better for you.

Standup 01/17/2008

edit Posted by Chad Woolley on Thursday January 17, 2008 at 07:01PM

Interesting Things

  • There is a gotcha when creating a Ruby Hash with a default value. If you pass a object to the constructor, such as an empty hash, the same object will be used for all default values. That probably isn't what you want. Instead, use the form of the constructor which takes a block. Here is an illustration:

    $ irb 
    >> trickyhash = Hash.new({})
    => {}
    >> trickyhash[:a][:a] = 1
    => 1
    >> trickyhash[:b]
    => {:a=>1}
    >> betterhash = Hash.new {|h,k| h[k] = {} } 
    => {}
    >> betterhash[:a][:a] = 1
    => 1
    >> betterhash[:b]
    => {}
    
  • ruby-prof and KCachegrind are very useful for profiling and performance optimization. We had problems compiling the OS X Darwin Port of KCachegrind, though - you may just want to run it on linux.

  • Vine Server and Viewer 3.0 has been released.

Ask for Help

  • "QuickSilver for Dummies?" - What is a good resource to learn about QuickSilver?

Standup 01/16/2008

edit Posted by Chad Woolley on Wednesday January 16, 2008 at 08:02PM

Ask for Help

  • "Does Intellij Idea sometimes do an SVN up without asking?"
    • Sometimes, if you do an svn up on the command line, IntelliJ will not always pick up the changes. You need to make sure you click the "refresh" button in the version control "Changes" view, not just the "synchronize" button on the main toolbar.

Standup 01/15/2008

edit Posted by Chad Woolley on Wednesday January 16, 2008 at 04:03AM

Ask for Help

  • "Can you use Google Maps on an https page?"
    • Probably via an iframe. Is there a preferred way?

ruby-debug in 30 seconds (we don't need no stinkin' GUI!)

edit Posted by Chad Woolley on Tuesday January 08, 2008 at 08:30AM

Alfonso Bedoya, Treasure of the Sierra Madre

Many people (including me) have complained about the lack of a good GUI debugger for Ruby. Now that some are finally getting usable, I've found I actually prefer IRB-style ruby-debug to a GUI.

There's good tutorial links on the ruby-debug homepage, and a very good Cheat sheet, but I wanted to give a bare-bones HOWTO to help you get immediately productive with ruby-debug.

Install the latest gem

$ gem install ruby-debug

Install the cheatsheet

$ gem install cheat
$ cheat rdebug

Set autolist, autoeval, and autoreload as defaults

$ vi ~/.rdebugrc
set autolist
set autoeval
set autoreload

Run Rails (or other app) via rdebug

$ rdebug script/server

Breakpoint from rdebug

(rdb:1) b app/controllers/my_controller.rb:10

Breakpoint in source

require 'ruby-debug'
debugger
my_buggy_method('foo')

Catchpoint

(rdb:1) cat RuntimeError

Continue to breakpoint

(rdb:1) c

Next Line (Step Over)

(rdb:1) n

Step Into

(rdb:1) s

Continue

(rdb:1) c

Where (Display Frame / Call Stack)

(rdb:1) where

List current line

(rdb:1) l=

Evaluate any var or expression

(rdb:1) myvar.class

Modify a var

(rdb:1) @myvar = 'foo'

Help

(rdb:1) h

There are many other commands, but these are the basics you need to poke around. Check the Cheat sheet for details.

This can also be used directly from any IDE that supports input into a running console (such as Intellij Idea).

That should get you started. So, before you stick in another 'p' to debug, try out ruby-debug instead!

The Power of Versions (Monkey Patches Targeted with Friggin Laser Beams!)

edit Posted by Chad Woolley on Friday January 04, 2008 at 05:32PM

We all love to Monkey Patch Rails and other Ruby apps. However, we sometimes want to target these patches to the specific versions where they are needed.

Here's the easiest way to do this, via RubyGem's built-in version requirement support. The version 0.11.0 should indeed be greater than version 0.9.0:

irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> Gem::Version::Requirement.new(['> 0.9.0']).satisfied_by?(Gem::Version.new('0.11.0'))
=> true

Notice that you can't do this with string comparison, because with a per-character comparison,1 is not greater than 9:

irb(main):001:0> '0.11.0' > '0.9.0'
=> false

Here's a little class which puts some helper and example methods around this approach (these methods are all in real use for some of our multipart mailer hacks):

module Pivotal
  class VersionChecker
    def self.current_rails_version_matches?(version_requirement)
      version_matches?(Rails::VERSION::STRING, version_requirement)
    end

    def self.version_matches?(version, version_requirement)
      Gem::Version::Requirement.new([version_requirement]).satisfied_by?(Gem::Version.new(version))
    end

    def self.rails_version_is_below_2?
      result = Pivotal::VersionChecker.current_rails_version_matches?('<1.99.0')
      result
    end

    def self.rails_version_is_below_rc2?
      Pivotal::VersionChecker.current_rails_version_matches?('<1.99.1')
    end

    def self.rails_version_is_1991?
      Pivotal::VersionChecker.current_rails_version_matches?('=1.99.1')
    end
  end
end

(note: some angle brackets changed due to code formatting bug)

Here's an example of how you'd use this:

if Pivotal::VersionChecker.rails_version_is_below_2?
  # do some backward compatibility stuff
  # or handle bugs that have been fixed in Rails > 2
end

Note that this is only possible now that Rails has started using a more sensible strategy for versioning edge gems and improved support for using advanced versioning with RAILS_GEM_VERSION.

For many projects, this may be overkill. It is useful at Pivotal, though, where many various projects may be on different rails versions, but still want to use the latest common core libraries (and monkey patches) without having to upgrade Rails for their app.

This isn't only useful for monkey patching. It can be handy for any library that wants to be backward- or forward-compatible with its dependencies. I've used this approach at Pivotal and on my personal projects to have Continuous Integration automatically run my tests against multiple dependency versions, without having to change anything other than the CI project name:

'GemInstaller Continuous Integration automatically running against multiple versions of RubyGems'

There are numerous other related topics for discussion in this area, such as the power of versions or the wisdom of freezing, but I'll save those for future posts. Even if you do freeze the trunk of Rails/plugins/gems, since the version is included in the source, this approach should work barring any conflicts with trunk changes since the last release.

Happy Versioning!

Standup 06/28/2007

edit Posted by Chad Woolley on Thursday July 05, 2007 at 09:25PM

Interesting Things

  • You can do single key presses in selenium with key-press. This is very useful in some scenarios - for example, predictive typing in search fields.

Standup 06/27/2007

edit Posted by Chad Woolley on Thursday July 05, 2007 at 09:23PM

Interesting Things

  • Don't forget about the 'net' tab in the FireBug firefox extension. This can take the place of other separate plugins such as Live HTTP Headers.

Other articles: