Figuring out whats wrong in Ruby can be a pain. That dynamic typing that you find so nice while writing code can sometimes work against you when reading it and troubleshooting it. What most of us end up resorting to is basically one step up from how most JS debugging happens: puts.

While this is annoying, it doesnt have to be this way. Ruby comes with a debugger, but it is slow on non-trivial applications. The best alternative is a gem called Ruby Debug, which is fast and has a bunch of goodies. I come from the GUI-debugging world of VS.NET and IDEA, so getting into Ruby Debug was a little bit of a challenge for me at first. If you come from the gdb world you should feel right at home.

Watch the Ruby Debug Basics screencast

from the screencast: fib.rb

  1. def fibn
  2. @fib_cache ||= 1, 1
  3. @fib_cachen ||= fibn-1 + fibn-2
  4. end
  5. puts fib20

Next screencast will cover debugging a Rails application.

ruby on rails

Ruby is a great language. Really. How many other languages let you extend other classes? Modify their behavior? Overload operators? With great power comes great opportunity, and in this post Ill cover one of my recent extensions to Ruby that was recently accepted into Rails core.

Date and Time

Managing dates and times is not exactly fun in any language. There are time zones, leap years, two meridians, twenty-four hours, 365 days (sometimes), and a mess of inconsistently long months. Those of us who use Ruby frequently are familiar with how to get objects corresponding to the current time and the current day:

  1. >>
  2. => Thu Jan 25 20:12:50 -0800 2007
  3. >>
  4. => #<Date: 4908251/2,0,2299161T>

Sexy methods

Rails has these really cool extensions to Numeric that allow computing lengths of time in a more human-readable way. For example, if I wanted to figure out how long 12 hours is, I could just call 12.hours and get back the number of seconds in 12 hours, which could then be conveniently added to an instance of Time, like so:

  1. >> t =
  2. => Thu Jan 25 19:31:17 -0800 2007
  3. >> t + 12.hours
  4. => Fri Jan 26 07:31:17 -0800 2007

Sweet! Whats even cooler though is that, in addition to Numeric with seconds, minutes, hours, days, weeks, fortnights, months, and years, we also get from_now, ago, since, and until:

  1. >>
  2. => Fri Jan 26 19:34:20 -0800 2007
  3. >> 2.weeks.ago
  4. => Thu Jan 11 19:34:35 -0800 2007

but kinda dumb.

Nice! These are so easy to read. These were great for simple things, but since they returned numbers, they couldn’t take into account the current date and how many days were in a month, leap year, etc. Notice that this causes problems when the month doesn’t have 30 days in it:

  1. >>
  2. => Thu Jan 25 21:01:31 -0800 2007
  3. >> 1.month.from_now
  4. => Sun Feb 24 21:01:34 -0800 2007

So its good for approximations, but not much else. Well what now?

A smart method

To compensate for the lack of accuracy in the above sexy methods, Time#advance was added to make it easy to do smart addition to Time instances. Here’s some of the above using advance:

  1. >> t =
  2. => Thu Jan 25 21:11:32 -0800 2007
  3. >> t.advance:hours => 12
  4. => Thu Jan 25 21:11:32 -0800 2007
  5. >> t.advance:months => 1
  6. => Sun Feb 25 21:11:32 -0800 2007

Excellent! Not quite as sexy, but definitely smart. A method suitable for Serious Business.

Smart n Sexy

I welcomed Time#advance, like everyone else, but I didnt want to give up the sexy methods. Fortunately, Ruby is great for letting objects masquerade as other objects (the whole duck typing thing), and the de-facto way to do this in Rails is by using Builder::BlankSlate, whose instance undefine almost all of their methods, allowing you to easily proxy all or some methods to something else. The two best examples of its use in Rails are AssociationProxy, which is used by Active Record, and JavaScriptGenerator, which is used by RJS.

To solve the problem, all we need to do is make the duration methods on Numeric return a proxy for the number they used to return which acts accordingly around Time and Date objects. This new class is located in ActiveSupport::Duration, and simply accumulates lengths of time for when it is used around a Time or Date, and a number for use around things that expect it to act like a number (i.e. for backward compatibility). Heres the new, smart and sexy, methods on Numeric:

  1. >> t =
  2. => Thu Jan 25 21:21:44 -0800 2007
  3. >> t + 1.month
  4. => Sun Feb 25 21:21:44 -0800 2007
  5. >> t + 1.week
  6. => Thu Feb 01 21:21:44 -0800 2007
  7. >> 1.year.from_now
  8. => Fri Jan 25 21:22:00 -0800 2008
  9. >> 4.years.from_now
  10. => Tue Jan 25 21:22:12 -0800 2011
  11. >> 3.weeks
  12. => 21 days

Hows that last one for overriding inspect? To try it out all you have to do is freeze edge in a Rails project near you!

$ rake rails:freeze:edge

Update: I should add that this recent change also corrected handling around Date objects. I implied that above, but I should be explicit. Before Duration, adding and didnt yield the expected results at all:

  1. >> +
  2. ArgumentError: time out of range

Now it behaves as expected:

  1. >> +
  2. => Sat Jan 27 00:00:00 -0800 2007