My .irbrc

Thursday, September 13

Pursuant to this ancient post regarding irb history and completion, here is my current .irbrc, now sporting a custom “Rails” section to make my life on the Rails console easier.

require 'irb/completion'
require 'irb/ext/save-history'

IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history" 
IRB.conf[:PROMPT_MODE]  = :SIMPLE

# Just for Rails...
if rails_env = ENV['RAILS_ENV']
  rails_root = File.basename(Dir.pwd)
  IRB.conf[:PROMPT] ||= {}
  IRB.conf[:PROMPT][:RAILS] = {
    :PROMPT_I => "#{rails_root}> ",
    :PROMPT_S => "#{rails_root}* ",
    :PROMPT_C => "#{rails_root}? ",
    :RETURN   => "=> %s\n" 
  }
  IRB.conf[:PROMPT_MODE] = :RAILS

  # Called after the irb session is initialized and Rails has
  # been loaded (props: Mike Clark).
  IRB.conf[:IRB_RC] = Proc.new do
    ActiveRecord::Base.logger = Logger.new(STDOUT)
    ActiveRecord::Base.instance_eval { alias :[] :find }
  end
end

I’m using the IRB.conf[:PROMPT] configuration option to create a custom Rails prompt that displays the current project name (which it assumes is the same as the PWD). Note that I’m also creating a convenience alias for AR::Base#find and enabling logging to STDOUT. Fun.

Impressed with Kijiji

Wednesday, September 12

I used Kijiji for the first time on the weekend, and I’m quite impressed. Kijiji is a free classified listing application created by the folks at eBay. It’s kind of like if craigslist and eBay had a baby.

My wife and I just bought a new house, and like most houses, it came with appliances. They weren’t the greatest, though, and we decided to replace them. The problem was, I didn’t know what to do with them. I don’t have a truck to take them to the dump, and I didn’t want to put them out on the end of the driveway and wait for them to be scavenged. The fridge I was able to give to a friend who needed it, but I didn’t know anyone who needed a stove. I didn’t want any money for it. I just wanted rid of it.

I thought of craigslist, but my local niagara.craigslist.com isn’t very active, and I doubted I’d get a reply in a timely fashion. My dad (of all people) suggested I try Kijiji. So, I posted it on Kijiji for and within an hour I had 10 replies. By the time I heard back from the first respondent, 3 more replies had come in. It was astonishingly fast for an area of this size. I really didn’t expect there to be so many users watching the listings.

The “winner” was from about 20 minutes away, and he came right over with his truck and his son, and loaded up the stove. We shook hands, he said thanks, and that was that.

Good things about Kijiji

One of my favorite things about Kijiji is how easy to use it is. You don’t even need to sign up to post a listing. Just your email will suffice, provided you confirm it. The listings themselves are sparse, consisting of just a title, a description, a price, and up to five image uploads. The images have a live preview and upload with a nice progress bar, so you can see what you’ve uploaded before you save your listing. If you enter your address with your listing, it will be automatically linked to a map, so people can tell whether or not you’re close by. (Unfortunately it’s a primitive non-Ajax mapquest map.)

The control panel (if you can call it that) is incredibly light. You can see your listings and choose to edit or delete them. You can also change your password. That’s it. When you’re done with your listing, you simply delete it.

People communicate with you by filling out the captcha-enabled contact form that’s on every listing. The email arrives with the sender’s name in the reply-to header, so you just reply to the email directly and call it a day. Nobody ever sees your email address unless you choose to reply.

They avoid listing spam by limiting the number of communities you can simultaneously post to, and by limiting the number of listings you can create in a single day. I found there was a lot less cruft in the listings than on craigslist. It was a lot more focused, and things are easy to find.

All in all, I found it a lot simpler and a lot more approachable than craigslist. Especially from a friendly-interface perspective. I could never get my parents to use craigslist, but they’ve already been using Kijiji for a few months and love it. They’ve sold a few antiques, a riding lawnmower, and have even made a few purchases.

Array#extract_options!

Tuesday, September 11

Rails (really, ActiveSupport) now sports a nifty new addition to Array to encapsulate the pattern of getting an options hash out of a variable number of arguments: extract_options!

If the last item in an array is a Hash, extract_options! removes and returns it. Otherwise, it just returns an empty Hash. This is primarily useful when you have a method that accepts a variable number of arguments (*args), the last of which is to be a hash of options. This is a common idiom in the Rails source code.

def options(*args)
  args.extract_options!
end

options # => {}
options(:name => 'foo', :format => 'text') # => { :name => 'foo', :format => 'text' }

This is cleaner than the way this is normally done:

def options(*args)
  options = args.last.is_a?(Hash) ? args.last : {}
end

You gotta love ActiveSupport.

ActiveRecord, quickly

Thursday, September 06

I often want to experiment with a database model using ActiveRecord, from outside the context of a Rails application. Ideally, I want to do this all in one file. Where I can see my migrations and my models at the same time and tweak as needed.

This is the stub I’ve been using lately for that task.

require 'rubygems'
require 'active_record'

ActiveRecord::Base.logger = Logger.new(STDOUT) if 'irb' == $0

ActiveRecord::Base.establish_connection(
  :adapter  => 'mysql',
  :database => 'example',
  :username => 'root',
  :host     => 'localhost'
)

ActiveRecord::Base.silence do
  ActiveRecord::Schema.define(:version => 1) do
    with_options :force => true do |m|
      m.create_table 'examples' do |t|
        t.string :title
        t.timestamps
      end
    end
  end
end

class Example < ActiveRecord::Base
end

if __FILE__ == $0
  require 'test/unit'

  class TestExample < Test::Unit::TestCase
    def test_should_flunk
      flunk
    end
  end
end

I simply define all my migrations and each model class here, and then write a few tests to ensure things are working the way I expect. Changing the schema and adding/removing fields is a snap, and the database tables are dropped and recreated each time the file is run.

The tests are run selectively, and AR::Logger is set to STDOUT when $0 is irb because I often want to play with my creation interactively on the console. This helps me get a sense of how things work, and how my objects feel from an API perspective.

Here’s what the stub above looks like from an irb session:

$ irb
>> require 'example_models'
-- create_table("examples", {:force=>true})
   -> 0.1467s
-- initialize_schema_information()
   -> 0.0006s
-- columns("schema_info")
   -> 0.0027s
=> true

>> Example.create!
  Example Columns (0.064651)   SHOW FIELDS FROM examples
  SQL (0.000134)   BEGIN
  SQL (0.000316)   INSERT INTO examples (`updated_at`, `title`, `created_at`) VALUES('2007-09-06 11:14:05', NULL, '2007-09-06 11:14:05')
  SQL (0.000682)   COMMIT
=> #<Example id: 1, title: nil, created_at: "2007-09-06 11:14:05", updated_at: "2007-09-06 11:14:05">
>> 

I find this to be a really fast way to prototype ideas.

Links for Today: 2

Wednesday, September 05

Again with the links! Let’s see how long I keep this up…

Links for today: 1

Tuesday, September 04

And now for something new. Links for today. Whatever. It’s new to me.

  • Has finder: a new ActiveRecord extension that makes it easier than ever to create custom find and count queries. Looks better than both of scope-out and scoped-proxy.
  • Zooom: window stuff for OS X. Done right.
  • Webistrano: a web front-end for Capistrano.
  • Seesaw: high-availability Mongrel Packs.
  • Sphincter: ActiveRecord extension for full-text searching with Sphinx.