Automated testing saves the day

I’m working on a Ruby on Rails application, where automated testing is an absolute must. Unlike Java or C++, you don’t have any kind of useful compile-time warnings and errors to tell you where you’ve screwed up, made a typo, etc. Most errors in a Rails web app happen when a user interacts with your code, so if you don’t test, you don’t know about bugs until it’s too late. This is one of many reasons I’m wishing for a nice C++ project to play with… but that’s another topic for another day…. Continue reading “Automated testing saves the day”

Why Ruby is so sexy-awesome, part XXXIV

I use Ruby whenever I can. Not specifically with Rails – Rails extends the language and adds some nifty things, but the beauty is all Ruby’s.

Today I was using Ruby (in a Rails app, as it happens), and I had this “API” that returns generic hash data. I want to be able to take data from any source (Oracle, flat text, web service) and return data that’s in a very simple and easy-to-use format, so I chose to just convert data to a hash on a per-source basis.

But how do I handle typos in hash keys? What if somebody asks for “person[:name]” when they’re supposed to ask for “person[:full_name]”? They just get blank data and wonder WTF happened…. I can’t live with this situation, because it’s just too easy to forget a key’s name, or make a simple typo. I could return default data from the hash, such as “YOU FUCKED UP WITH YOUR KEY, SIRS”, but that could find its way into production and then I’m out a job.

So after a tiny bit of digging, I discovered that a Hash can not only have a default value, but also call a default block when a nonexistent key is requested:

irb(main):001:0> a = Hash.new {|hash, key| raise "#{key} not found!"}
=> {}
irb(main):005:0> a[1] = :foo
=> :foo
irb(main):006:0> a[1]
=> :foo
irb(main):007:0> a[2]
RuntimeError: 2 not found!
irb(main):008:0> a.default = nil
=> nil
irb(main):009:0> a[2]
=> nil

Normally I’m good with non-strict default data, but in this case it’s great to know I can actually validate data in a way that makes it hard to miss typos.

It’s not as safe as C++ (edge cases are only caught at runtime), but it’s far better than Perl (and nicer to read or write than both, IMO).