Read ActiveRecord columns directly from the class

Sometimes you want to read just a single column from a collection of records, without the overhead of instantiating each and every one. You could just execute raw SQL, but it's a shame to do away with the nice type conversion ActiveRecord provides. It'd also be a pity to get rid of find scoping, amongst other goodness.

Enter Tomafro::ColumnReader:

module Tomafro::ColumnReader
  def column_reader(column_name, options = {})
    name = options.delete(:as) || column_name.to_s.pluralize
    column = columns_hash[column_name.to_s]
    
    self.module_eval %{
      def self.#{name}(options = {})
        merged = options.merge(:select => '#{column_name}')
        connection.select_all(construct_finder_sql(merged)).collect do |value| 
          v = value.values.first
          #{column.type_cast_code('v')}
        end
      end
    }
  end
end

Once you've extended ActiveRecord::Base with it, usage is simple. In your models, declare which columns you want access to:

ActiveRecord::Base.extend Tomafro::ColumnReader
 
class Animal < ActiveRecord::Base
  column_reader 'id'
  column_reader 'name'  
 
  named_scope :dangerous, :conditions => {:carnivorous => true} 
end

Once you've done this, you can access values directly from the class, respecting scope, limits and other finder options.

Animal.names 
#=> ['Lion', 'Tiger', 'Zebra', 'Gazelle']
 
Animal.names :limit => 1 
#=> ['Lion'] (Normal finder options supported)
 
Animal.dangerous.names 
#=> ['Lion', 'Tiger'] (Scoping respected)
 
Animal.ids
#=> [1, 2, 3] (Values cast correctly)

An Objective-C implementation of ActiveSupport's Inflector

Over the last week I've been playing with Objective-C, for fun rather than profit. Here's the first result of this dabbling - an Objective-C implementation of ActiveSupport's pluralize and singularize methods.

It's my first piece of code in the language, so I'd appreciate comments and feedback.

I thought we were going to Kew Gardens

Using Rack Middleware for good and evil

So we all know that Rack is awesome, and that we can use Rack::Middleware for all sorts of things: debugging, caching and a whole host more.

What all these have in common (apart from maybe Rack::Evil) is that they're all helpful. They all make writing Rack applications easier. Not my Middleware though.

Introducing Rack::Shuffler

module Rack
  class Shuffler
    def initialize(app)
      @app = app
      @responses = []
    end
    
    def call(env)
      @responses << @app.call(env)
      @responses[rand(@responses.size)]
    ensure
      @responses.delete_at(rand(@responses.size)) if @responses.size > 100
    end
  end
end

I suggest you add it to a colleague's app late on a Friday afternoon, and see how long it takes to drive them to insanity.

If imitation is the sincerest form of flattery...

...consider me flattered.

Automatching rails paths in cucumber

If you're using cucumber as part of your testing, you probably have a paths.rb file that looks something like this:

module NavigationHelpers
  def path_to(page_name)
    case page_name
    
    when /the home page/
      root_path
    when /the new client page/
      new_client_path
    when /the clients page/
      clients_path    
    # Add more page name => path mappings here
    else
      raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
      "Now, go and add a mapping in features/support/paths.rb"
    end
  end
end

World(NavigationHelpers)

This let's us use nice descriptive names in our scenarios, but it starts to become a pain when we add more and more paths. So how can we make it better?

By automatically matching some rails paths. Here's the code:

module NavigationHelpers
  def path_to(page_name)
    case page_name
    
    when /the home page/
      root_path   
    # Add more page name => path mappings here
    else
      if path = match_rails_path_for(page_name) 
        path
      else 
        raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
        "Now, go and add a mapping in features/support/paths.rb"
      end
    end
  end

  def match_rails_path_for(page_name)
    if page_name.match(/the (.*) page/)
      return send "#{$1.gsub(" ", "_")}_path" rescue nil
    end
  end
end

World(NavigationHelpers)

What it does is pretty simple. Given a page name the clients page (with no other matches defined) it will try and send clients_path. If successful, then it returns the result, otherwise nil.

Not the biggest improvement in the world, but it's made my cucumber tests just a little bit easier to write.

Adam Sanderson's open_gem

The latest version of rubygems (1.3.2) now has an interface to add commands. Making great use of this feature, Adam Sanderson has written open_gem, a simple but amazingly useful tool.

You use it like this:

$ gem open activerecord

This opens the activerecord gem in your favourite editor (taken from either $GEM_OPEN_EDITOR or $EDITOR environment variables). If there are multiple versions of the gem installed, it will show a menu, letting you choose which version you require.

$ gem open activerecord
Open which gem?
 1. activerecord 2.1.0
 2. activerecord 2.3.2
> 

open_gem itself is a gem, and can be installed with:

$ gem install open_gem

To get it working, you need to have $EDITOR set to something sensible:

$ export EDITOR=mate

If you're running on OS X and use TextMate, you may have already set $EDITOR to mate -w, which let's you use TextMate as the editor for git commit messages and much more. However, the -w flag doesn't work with open_gem, so set the $GEM_OPEN_EDITOR variable, and open_gem will use that instead:

$ export GEM_OPEN_EDITOR=mate

You should now be good to go. If you want to see how it works, just use it on itself!

$ gem open open_gem