5 Core Extension Tips

April 28th, 2008

We’re all familiar with Rails’ core extensions. They’re the Ruby class extensions that allow you do things like:

30.minutes.ago

"octopus".pluralize

["Lifeson", "rocks", "hard."].to_sentence

Now, I often find myself writing Rails helper methods that act on Ruby classes (String, Array, etc.). But to keep my code clean, I like to refactor these helpers as core extensions. This is a useful refactoring pattern for Rails applications. We might call it

  • Replace Core Class Helper with Core Extension.

I’m going to show you how to include core extensions in your Rails app. Then, I’ll describe four extensions that I commonly use.

1. Write Your Own Core Extensions

First, create a module, name it core_extensions.rb, and store it in your /lib folder.

module CoreExtensions

end

Then, at the very end of your environment.rb file, require the CoreExtensions module.

require 'core_extensions'

2. Format a string as a possessive.

These two methods extend the String class. The first returns the last character of a string. The second produces the possessive (’s) form.

class String

def last
  self[self.length-1].chr
end

def possessive
  self.last == 's' ? (self + "\'") : (self + "\'s")
end

end

Here’s how it works:

"Joe".last
=> "e"
"Joe".possessive
=> "Joe's"

3. Format Time as Month / Day / Year
Times needs to be formatted in all kinds of ways. Here’s just one example:

class Time
  def m_d_y
    self.strftime("%B %d, %Y")
  end
end

And it works like so:

Time.now.m_d_y
=> "April 28, 2008"

4. Display an array of ActiveRecord objects.
It is often necessary to iterate through an array of ActiveRecord objects, surrounding each with an html tag. Here’s an extension to array to automate this:

class Array
  def each_with_tag(start_tag, end_tag, attribute)
    to_display = []
    self.each do |element|
      if element.respond_to?(attribute)
        to_display << (start_tag + element.send(attribute) + end_tag)
      else
        raise ArgumentError, "object does not respond to #{attribute}"
      end
  end
  return to_display.join("\n")
end

How does it work? Say you have a recipe application. You need to display a list of recipe titles, each within a paragraph element:

@recipes.each_with_tag('<p>', '</p>', :title)

=> "<p>Spinach Lasagna</p>"

"<p>Raspberry Tart</p>"

5. Get class name as string.
Here’s a simple method that comes in handy when using inheritance. Sometimes, you just don’t know what sort of object you’re dealing with. The class_name method does just what it says, giving you an easy way to display information about your object.

class Object
  def class_name
    self.class.to_s.downcase
  end
end

Suppose I have a class modeling vegetables in a garden. If I needed to display a message about a particular vegetable, I could use class_name like so:

"A " + @veggie.class_name + " should be watered " + @veggie.watering_rate + " times per week."

=> "A tomato should be watered two times per week."

Summary

Next time you write a helper that acts on a basic Ruby class, consider writing a core extension instead. Using core extensions can help create more elegant, portable, maintainable code.

Leave a comment