Extending and Modifying Preexisting Code

When I introduce Ruby to new students, my first example is often meant to shake them up a little. It is relatively unremarkable, but to those who have not worked in languages with an open class system before, it can be quite alarming:

class Fixnum

  def +(other)
    42
  end

end

The implications typically don’t sink in until I fire up irb:

>> 2 + 2
=> 42

This demonstration is typically followed by a firm “never do this” reminder, but I continue to use it because it opens people’s eyes to just how different Ruby is from most other languages. The standard response to this example is a flurry of questions about how Rubyists manage to make heads or tails of things when people can go all willy-nilly with extending classes as they see fit. That’s what this section is all about.

We’re going to talk about two related but somewhat distinct topics here. The first is extending Ruby classes with new behaviors by reopening classes; the second is actually modifying existing behaviors to fit new requirements. What separates the two is primarily the level of controversy, and hence the necessary level of care.

Because adding new functionality is the less dangerous of the two, we’ll start with that and go over some of the specifics.

Adding New Functionality

In Chapter 1, Driving Code Through Tests, I mentioned and made use of a small extension to Test::Unit that dynamically defines test methods for us. As previously mentioned, we’ve borrowed this functionality ...

Get Ruby Best Practices now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.