Hashes and Frozen Keys

Posted on August 21, 2009, under Coding.

The hash class freezes keys that are strings:

This can be a problem if you want to use those keys later on…more specifically, if you want to extract and edit those strings:

Unfortunately, those strings will have to be duped or cloned:

Sinatra and Passenger/mod_rails

Posted on August 13, 2009, under Coding.

If you want Apache to serve up a Sinatra app, your best bet is to use Passenger (AKA mod_rails).

All your app needs is the usual Rackup config file (config.ru) in the app’s root directory, and the directory public/ .

There’s one caveat, though: if you have a file named environment.rb , do not put it in config/ .

If mod_rails finds config/environment.rb , it’ll think your app runs on Rails:

Ruby in Etch

Posted on February 5, 2009, under Coding, GNU/Linux.

As some of you may know, Ruby and Debian’s ways of packaging software go together like Darwin and religious zealots…as in, they don’t. So how should you install Ruby when using Debian Stable? How do you stay up-to-date with new versions of Ruby and gems?

By using Backports, and not worrying so much.

First, setup your box to be able to install backports of packages. Next, uninstall any Ruby-related packages. Yeah, that’s right. Do you know why? Because, if you’re running Etch, you’re using Ruby 1.8.5! Egad! That’s almost medieval. Make sure to uninstall irb and rdoc, too.

Now it’s time to install shinier versions…1.8.7, to be exact:

$ sudo aptitude install -t etch-backports libruby1.8 ruby1.8 rdoc1.8 irb1.8

All of that should be on one line.

There you have it. Now you’ve got Ruby 1.8.7 on Debian Stable (AKA “Etch”). Ruby’s not complete without RubyGems, though. Download the latest version to /usr/src/ , and extract it:

$ cd /usr/src/$ wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz$ tar zxf rubygems-1.3.1.tgz

Then run the setup utility:

$ cd rubygems-1.3.1/$ sudo ruby setup.rb

Let’s do one last thing to make life easier. The RubyGems setup script installed the “gem” command as /usr/bin/gem1.8 . I don’t want to have to type that “1.8″ every time.

$ cd /usr/local/bin/$ sudo ln -v -s /usr/bin/gem1.8 gem

There. Now we can run “gem” like the rest of the world.

Easy? Yar.

Default stegosaurses

Posted on January 28, 2009, under Coding, Ruby.

Ever heard of Jonathan Viney’s active_record_defaults plugin? It’s fantastic. In a nutshell, it enables you to specify default values for model attributes. If an attribute isn’t set when initialising a new instance, the attribute’s set to whatever the default value is.

For example, let’s rebuild that Stegosaurus class from a previous post:

class Stegosaurus < ActiveRecord::Base  attr_accessible :tail_spikes, :back_plates

  validates_numericality_of :tail_spikes,     :o nly_integer             => true,    :greater_than_or_equal_to => 0

  validates_numericality_of :back_plates,     :o nly_integer             => true,    :greater_than_or_equal_to => 0end

With that, if we created a new Stegosaurus and didn’t specify any attributes, not only would it have no tail spikes or back plates, but the model instance wouldn’t be valid.

To fix that, all we need to do is add two lines:

class Stegosaurus < ActiveRecord::Base  attr_accessible :tail_spikes, :back_plates

  default :tail_spikes => 4  default :back_plates => 6

  validates_numericality_of :tail_spikes,     :o nly_integer             => true,    :greater_than_or_equal_to => 0

  validates_numericality_of :back_plates,     :o nly_integer             => true,    :greater_than_or_equal_to => 0end

And voila, new Stegosaurus objects will automatically have 4 tail spikes and 6 back plates:

>> s = Stegosaurus.new=> #<Stegosaurus tail_spikes: 4, back_plates: 6>>> ?> s.tail_spikes=> 4>> s.back_plates=> 6

However, if used improperly, this can lead to several hours of pounding your head on your desk. Note that that the default values we used above, 4 and 6, are immutable objects. You can’t change them. You can perform operations on them, such as addition (4 + 1), but that never changes the object.

Say we want our Stegosaurus class to have an array specifying its diet that defaults to “fern” and “cycad”:

class Stegosaurus < ActiveRecord::Base  attr_accessible :tail_spikes, :back_plates, :diet

  default :tail_spikes => 4  default :back_plates => 6  default :diet => %w(fern cycad)

  validates_numericality_of :tail_spikes,     :o nly_integer             => true,    :greater_than_or_equal_to => 0

  validates_numericality_of :back_plates,     :o nly_integer             => true,    :greater_than_or_equal_to => 0end

That looks right. But watch this:

=> charles = Stegosaurus.new=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>>> ?> arnold = Stegosaurus.new=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>>> ?> charles.diet < < 'moss'=> ["fern", "cycad", "moss"]>> ?> arnold.diet=> ["fern", "cycad", "moss"]

We didn’t mean to do that…Arnold doesn’t want to eat moss!

At the moment, when the Stegosaurus class is initialised, it creates one Array for the default “diet” attribute of all future Stegosaurus objects. In other words, Charles’ and Arnolds’ “diet” attributes were references to the same object:

>> charles.diet.object_id=> 19103090>> ?> arnold.diet.object_id=> 19103090

How do we fix that? We tell the Stegosaurus class to create a new Array for each model instance. Simply change this:

default :diet => %w(fern cycad)

to this:

default :diet => Proc.new { %w(fern cycad) }

Now each time we create a new Stegosaurus, that Proc will fire, and create a new “diet” Array:

=> charles = Stegosaurus.new=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>>> ?> arnold = Stegosaurus.new=> #<Stegosaurus tail_spikes: 4, back_plates: 6, diet: ["fern", "cycad"]>>> ?> charles.diet < < 'moss'=> ["fern", "cycad", "moss"]>> ?> arnold.diet=> ["fern", "cycad"]

I highly recommend giving active_record_defaults a try. It’s very handy, and very easy to use.

And by the way, yes, I was bitten by this problem. Why else would I be writing about it! Can you guess how I discovered it, though? … My tests picked it up!

Toblerone

Posted on January 23, 2009, under Other.

Why is Toblerone so damn tasty? Y’know what? It doesn’t matter. All that matters is access to it when desired. My parents each gave me a huge Toblerone bar for Christmas. The first one went quickly, and I’ve been savouring the second one…but it’s nearly done, too!

Windows Preview: BSOD

Posted on January 16, 2009, under Other.

The power went out last night, so I’m at my Dad’s house right now, leeching his heat, electricity, and intertubes connection.

I opened up Finder, and noticed that MacOS had found a computer on the LAN. I clicked “Get Info” on it, and well..I’ll let the image speak for itself:

What Apple thinks of Windows
I love finding small touches like that. It reminds me that there are real people at work behind the things we use every day.

Friends don’t let friends code without tests

Posted on January 8, 2009, under Coding.

But what if your friends don’t write tests? Or what if you’re just lazy? Well, if the latter applies, that’s your own damn fault. But if nobody around you tests their code, you’re probably not going to be motivated to test your own code. But, fear not! RSpec is here!

RSpec is a really awesome testing framework. By “awesome”, I mean that it:

  • makes it easy to write tests;
  • makes your tests easy to read;
  • gives you an easy development path to follow.

It accomplishes this by following behaviour-driven development (BDD). If you’re not a keener, don’t bother following that link. Just read on for the stegosaurus.

With BDD, you write specs that describe your application’s behaviour in terms of what it should and shouldn’t do.

Let’s write an app to mimic one of my favourite dinosaurs. And while we’re at it, we’ll do some testing. But first, install RSpec:

sudo gem install rspec

Stegosauruses are known for 2 things. Let’s start with those awesome tail spikes:

class Stegosaurus  attr_accessor :tail_spikesend

That’s pretty simple. So how do we spec this? We start off by describing what we want our application to do. In this case, we should be able to grab the “tail_spikes” attribute:

require 'stegosaurus'

describe Stegosaurus doit 'should have tail spikes' do  steggie = Stegosaurus.new

  steggie.should respond_to :tail_spikes  steggie.should respond_to :tail_spikes=endend

Run the spec, and we’re off to the races!

$ spec stegosaurus_spec.rb.

Finished in 0.015328 seconds

1 example, 0 failures

We should also spec setting the number of tail spikes, so let’s update the spec:

require 'stegosaurus'

describe Stegosaurus doit 'should have tail spikes' do  steggie = Stegosaurus.new

  steggie.should respond_to :tail_spikes  steggie.should respond_to :tail_spikes=

  steggie.tail_spikes = 4  steggie.tail_spikes.should equal 4endend

That’s one of the most readable and easy-to-understand tests you’ve ever seen, eh?

Stegosauruses are also known for the huge plates on their backs:

class Stegosaurusattr_accessor :tail_spikesattr_accessor :platesend

The spec should be pretty obvious:

require 'stegosaurus'

describe Stegosaurus doit 'should have tail spikes' do  steggie = Stegosaurus.new

  steggie.should respond_to :tail_spikes  steggie.should respond_to :tail_spikes=

  steggie.tail_spikes = 4  steggie.tail_spikes.should equal 4end

it 'should have plates' do  steggie = Stegosaurus.new

  steggie.should respond_to :plates  steggie.should respond_to :plates=

  steggie.plates = 12  steggie.plates.should equal 12endend

Notice, though, that we’re beginning to repeat ourselves. In both of those examples (#it blocks), we create a new Stegosaurus. Let’s tidy that up a bit:

require 'stegosaurus'

describe Stegosaurus dobefore :each do  @steggie = Stegosaurus.newend

it 'should have tail spikes' do  @steggie.should respond_to :tail_spikes  @steggie.should respond_to :tail_spikes=

  @steggie.tail_spikes = 4  @steggie.tail_spikes.should equal 4end

it 'should have plates' do  @steggie.should respond_to :plates  @steggie.should respond_to :plates=

  @steggie.plates = 12  @steggie.plates.should equal 12endend

What we did there is tell RSpec to create a new Stegosaurus before each example is run. To make the stegosaurus available to the examples, it simply needs to be an instance variable.

When running your specs, there are a few different ways to format the output. I tend to use the default and “specdoc” formats. Currently, our spec’s output looks like this:

$ spec stegosaurus_spec.rb..

Finished in 0.01591 seconds

2 examples, 0 failures

But we can also tell RSpec to spit out a summary of our specs:

$ spec stegosaurus_spec.rb --format specdoc

Stegosaurus- should have tail spikes- should have plates

Finished in 0.057443 seconds

2 examples, 0 failures

Our Stegosaurus class is feeling a bit weird, though..technically, we can set the “tail_spikes” and “plates” attributes to any object:

$ irb>> require 'stegosaurus'=> true>>?> steggie = Stegosaurus.new=> #<Stegosaurus:0x602afc>>>?> steggie.tail_spikes = "we don't want to be able to do this!"=> "we don't want to be able to do this!"

So we need to restrict those two attributes to integers:

class Stegosaurusattr_reader :tail_spikesattr_reader :plates

def tail_spikes=(number_of_tail_spikes)  raise ArgumentError, 'The first argument (number_of_tail_spikes) must be a Fixnum.' unless number_of_tail_spikes.is_a? Fixnum

  @tail_spikes = number_of_tail_spikesend

def plates=(number_of_plates)  raise ArgumentError, 'The first argument (number_of_plates) must be a Fixnum.' unless number_of_plates.is_a? Fixnum

  @plates = number_of_platesendend

With that done, what do we need to change in our specs? We need to spec the behaviour of the 2 new setter methods:

require 'stegosaurus'

describe Stegosaurus dobefore :each do  @steggie = Stegosaurus.newend

describe '"tail_spikes" attribute' do  it 'can only be set to an integer' do    Proc.new {      @steggie.tail_spikes = 'asdf'      }.should raise_error ArgumentError, 'The first argument (number_of_tail_spikes) must be a Fixnum.'

    @steggie.tail_spikes = 4    @steggie.tail_spikes.should equal 4  endend

describe '"plates" attribute' do  it 'can only be set to an integer' do    Proc.new {      @steggie.plates = 'asdf'      }.should raise_error ArgumentError, 'The first argument (number_of_plates) must be a Fixnum.'

    @steggie.plates = 12    @steggie.plates.should equal 12  endendend

Most of that is pretty self-explanatory. However, notice that we’ve just nested #describe inside of the original #describe…twice! We do this because it makes are specs read more fluidly, and it groups examples (#it blocks) together. And inside these inner-#describes, we can do anything we talked about earlier, like setup a before-block.

Let’s add one more attribute…a name:

class Stegosaurusattr_reader :tail_spikes, :plates, :name

def tail_spikes=(number_of_tail_spikes)  raise ArgumentError, 'The first argument (number_of_tail_spikes) must be a Fixnum.' unless number_of_tail_spikes.is_a? Fixnum

  @tail_spikes = number_of_tail_spikesend

def plates=(number_of_plates)  raise ArgumentError, 'The first argument (number_of_plates) must be a Fixnum.' unless number_of_plates.is_a? Fixnum

  @plates = number_of_platesend

def name=(name)  raise ArgumentError, 'The first argument (name) must be a String.' unless name.is_a? String

  @name = nameendend

And now the specs look like:

require 'stegosaurus'

describe Stegosaurus dobefore :each do  @steggie = Stegosaurus.newend

describe '"tail_spikes" attribute' do  it 'can only be set to an integer' do    Proc.new {      @steggie.tail_spikes = 'asdf'    }.should raise_error ArgumentError, 'The first argument (number_of_tail_spikes) must be a Fixnum.'

    @steggie.tail_spikes = 4    @steggie.tail_spikes.should equal 4  endend

describe '"plates" attribute' do  it 'can only be set to an integer' do    Proc.new {      @steggie.plates = 'asdf'    }.should raise_error ArgumentError, 'The first argument (number_of_plates) must be a Fixnum.'

    @steggie.plates = 12    @steggie.plates.should equal 12  endend

describe '"name" attribute' do  it 'can only be set to a string' do    Proc.new {      @steggie.name = ['not valid']    }.should raise_error ArgumentError, 'The first argument (name) must be a String.'

    @steggie.name = 'Rupert'    @steggie.name.should equal 'Rupert'  endendend

Let’s run that spec now:

$ spec stegosaurus_spec.rb..F

1)'Stegosaurus "name" attribute can only be set to a string' FAILEDexpected "Rupert", got "Rupert" (using .equal?)./stegosaurus_spec.rb:37:

Finished in 0.02225 seconds

3 examples, 1 failure

Hrmmm, that’s no good. But that’s a fairly useful error message, eh?…well, sort of. It’s telling us what it expected, and what it received. The thing is, it expected “Rupert” and got “Rupert”, so what’s going on? The problem lies in the fact that you can’t use #equal? to compare strings, and that’s exactly what we’re doing. If you don’t believe me, try it for yourself:

$ irb>> 'Rupert'.equal? 'Rupert'=> false

BTW, did you notice the “(using .equal?)” hint that RSpec gave us?

Enough banter. All we need to do is change this:

@steggie.name.should equal 'Rupert'

to this:

@steggie.name.should == 'Rupert'

Shall we view our specs in all their glory now?

$  spec stegosaurus_spec.rb --format specdoc

Stegosaurus "tail_spikes" attribute- can only be set to an integer

Stegosaurus "plates" attribute- can only be set to an integer

Stegosaurus "name" attribute- can only be set to a string

Finished in 0.018755 seconds

3 examples, 0 failures

Those’re the absolute basics of RSpec. If you’re thirsty for more, check out the RSpec website.

Testing…it’s what life’s all about

Posted on January 7, 2009, under Coding.

I just read a great call to action by John Nunemaker. He wants to see everyone writing tests for their code, and has decided to “post like a superhuman fiend until everyone is testing”. He’s on to something!

With that said, I’m joining in. I primarily use RSpec, so I’ll be focussing on that, but we’ll give Cucumber and other tools a go, and we’ll be starting with the basics.

So subscribe to our feeds, and stay tuned!

CSS, Ruby, and breaks, oh my!

Posted on December 16, 2008, under Startups.

Today’s the 16th. I haven’t worked on YoDino since the 12th. Egad! What happened?! The usual “startup stress” happened.

I’ve been working pretty hard on getting the last important bits of YoDino implemented before Christmas. On the 11th, I started styling the app. On the 12th, my penchant for well-thought-out, structured, and predictable languages (<cough>Ruby</cough>) caused me to throw my hands in the air in frustration with CSS.

CSS…What an AWFUL language!

There, I said it. I don’t care if you can do awesome things with it, like CSS Zen Garden. Technically, you can do awesome things with Delphi and BASIC and ASP.NET, too. But I don’t do things with Delphi, BASIC or ASP.NET..and for very good reasons! [1] The same should apply to CSS, but there’s no alternative. Ugh.

Okay, tangent’s over. The frustration I felt from CSS was really blown out of proportion, but I think that’s because I’m doing this startup alone. It’s pretty much a fact that startups with multiple co-founders fare much better than startups with a single founder. Co-founders are able to discuss problems and ideas with each other, share frustrations, motivate each other, etc. They’re essentially a small, tight family.

I reckon my frustrations with CSS ended up being the straw that broke the camel’s back. I needed a break. So, you know what? I bloody well took one! [2]

Now, a couple of days later, I feel refreshed and ready to tackle it all again. And this time, I’m going to succeed. And CSS is going to be my bitch, not the other way around.

[1] If you have to ask why I don’t do things with Delphi, BASIC, or even ASP.NET, you’ve never experienced the clarity and melancholy of working in Ruby. Go try it. If, after a couple of days, you can honestly come back to me and say that you didn’t soil yourself from pure pleasure, I’ll buy you a beer.

[2] Yes, I know that once I launch YoDino, taking a break won’t be possible. But that’s okay! I’ll have made it through at least the first dip by then, and things will be different.

+1 for the thought, -10 for the execution

Posted on December 13, 2008, under Other.

I just received an email from the anti-virus company ESET, reminding me that a license that I purchased for one of their products is coming up for renewal soon. I appreciate the email, but honestly, do you think they could’ve put some more time into formatting it and making it readable and appealing?

!! ! PLEASE DO NOT REPLY TO THIS AUTOMATED EMAIL ! !————————————————————PLEASE IGNORE THIS ROBOT RENEWAL REMINDERIF YOU HAVE ALREADY RENEWED YOUR LICENSE————————————————————Dear valued client,Our records indicate that your ESET NOD32 Antivirus Systemlicense is due to expire on 31 December 2008.We often release several updates in a single day, but updatingstops when your license expires and your computer can quickly become dangerously exposed to brand new malware threats.Our offices will be minimally staffed from 22 December 2008 to 05 January 2009. We strongly recommend that you renew your license no later than 22 December 2008 to avoid deliverydelays.You won’t lose time or money by renewing early. You can useyour new license immediately, but the renewal period won’tcome into effect until your current license expires. (Licensesexpired for more than 30 days cannot be renewed!)You can renew with your local ESET reseller, or by phone on07 3325 2999 (9:00am-4:00pm Monday-Friday), or online on:http://www.eset.com.au/purchase/purchase.htmlYou can renew only the number of computers covered byyour current license. Please call for a quote to increase thenumber of computers.Regards,Joyita FewsterESET Australiaphone : 07 3325 2999 (9am-4pm EST Monday-Friday)website : http://www.eset.com.auemail : HYPERLINK “mailto:sales@eset.com.au”sales@eset.com.au_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/NOD32 is the outright winner of Australian PC User’s”Best Antivirus Program” / “Best Buy” Awards2001/2002/2003/2004/2005/2006/2007and has won more Virus Bulletin VB100% Awardsthan any other antivirus program in the world!_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/————————————————————PLEASE IGNORE THIS ROBOT RENEWAL REMINDERIF YOU HAVE ALREADY RENEWED YOUR LICENSE————————————————————! ! PLEASE DO NOT REPLY TO THIS AUTOMATED EMAIL ! !

Scanned by NOD32 ( http://www.eset.com.au )
and NetBox Blue ( http://netboxblue.com.au )

There isn’t a single newline in the message…WTF?