Topics Covered in This Ruby on Rails Tutorial:
Extending the String Class, Adding a New Method to the String Class
Exercise Overview
One of Ruby's most powerful features is its open class architecture, which allows you to reopen and extend any class—even after it's been defined. This capability enables you to add new methods to existing classes by simply opening a class declaration again and inserting additional functionality.
Consider this fundamental example (observe, but don't type it yet):
class Cat
end
class Cat
def meow
puts "Meow"
end
The second class declaration doesn't override the first—it seamlessly extends the original class with new functionality. This is Ruby's class reopening mechanism in action.
What makes Ruby truly exceptional is that this extensibility applies not only to your custom classes, but also to Ruby's core classes and Rails framework classes. This exercise will demonstrate how to leverage this power to extend fundamental Ruby classes, a technique that professional Rails developers use daily to create more expressive and maintainable code.
Ruby's ability to reopen classes is fundamental to its flexibility. When you declare a class multiple times, Ruby doesn't override the previous declaration - it simply adds new methods to the existing class definition.
Extending Core Ruby Classes
Let's explore how to extend Ruby's built-in String class with custom functionality that combines existing methods into more convenient operations.
If Interactive Ruby isn't running, open Terminal and launch the IRB console with the
irbcommand.Begin by creating a string instance to work with:
s = "Just a string"Verify the object's class by typing:
s.classThis confirms that our variable is indeed an instance of the
Stringclass.Ruby provides extensive built-in string methods. Let's refresh your memory by testing a few method combinations:
s.reverses.reverse.upcase
Notice how you can chain methods together—first reversing the string, then converting the result to uppercase. This method chaining is a hallmark of Ruby's fluent interface design.
Setting Up Your Ruby Environment
Launch Interactive Ruby
Open Terminal and type the irb command to start Interactive Ruby for hands-on practice with class extensions.
Create String Instance
Initialize a string variable with 's = "Just a string"' to use as your testing object.
Verify Class Type
Use s.class to confirm you're working with the String class before extending it.
Adding a New Method to a Core Ruby Class
Now we'll demonstrate Ruby's true power by creating a custom method that combines common operations. Imagine you frequently need to reverse and uppercase strings—instead of chaining methods repeatedly, let's create a single, reusable method.
Extend the String class by adding our custom method:
class String def reverse_caps self.reverse.upcase endNOTE:
selfrefers to the current string instance, allowing you to call methods on the string object itself.Test your new method:
s.reverse_capsTerminal returns the string reversed and uppercased:
GNIRTS A TSUJThis simple example showcases Ruby's philosophical approach to programming: the language should adapt to your needs, not the other way around.
This technique is foundational to Rails development. Rails itself extensively monkey-patches core Ruby classes to add functionality—methods like
5.days.agoor"admin".pluralizeare examples of Rails extending Integer and String classes. Popular gems follow this same pattern, which is why Ruby applications feel so naturally expressive. Understanding class extension is essential for any serious Rails developer.
self will return the current value of the string itselfMethod Chaining vs Custom Method
| Feature | Traditional Approach | Custom Extension |
|---|---|---|
| Code Length | s.reverse.upcase | s.reverse_caps |
| Readability | Multiple method calls | Single descriptive method |
| Reusability | Repeat everywhere | Define once, use anywhere |
Extending Another Core Ruby Class
Let's solidify this concept by extending the Array class, demonstrating how the same principles apply across different data types.
Create an array to work with:
a = [2,4, 6]Confirm its class type:
a.classNow extend the Array class with a custom mathematical operation:
class Array def square_all self.collect(&:abs2) endThis method squares each element in the array. The
abs2method returns the absolute value of a number squared, whilecollectapplies this operation to each array element. The&syntax converts the:abs2symbol into a block, creating clean, readable code.Execute the method:
a.square_allTerminal returns each number squared:
[4,16,36]Let's examine the
&:abs2shorthand syntax more closely. This Ruby idiom sends theabs2method to each element. See it in action:[2,4, 6].map(&:abs2)This shorthand is equivalent to writing a full block. Compare the results by typing:
[2,4, 6].map { |i| i.abs2 }You could even use the more explicit
sendmethod to achieve the same result:[2,4, 6].map { |i| i.send(:abs2) }All three approaches produce identical results, but the
&:syntax demonstrates Ruby's commitment to concise, expressive code. This syntactic sugar is why Ruby developers can write powerful applications with remarkably readable code.Keep IRB running as we continue exploring Ruby's capabilities in the next exercise.
Array Method Techniques
The abs2 Method
Provides the absolute value of an integer, squared. Essential for mathematical operations on array elements.
Symbol to Proc Conversion
The ampersand operator converts symbols to procs, enabling concise method calls on collection elements.
Three Ways to Square Array Elements
| Feature | Method | Syntax |
|---|---|---|
| Symbol to Proc | Most Concise | [2,4,6].map(&:abs2) |
| Block Syntax | Standard | [2,4,6].map { |i| i.abs2 } |
| Send Method | Verbose | [2,4,6].map { |i| i.send(:abs2) } |
Rails itself extensively uses core class extensions, and many gems follow this pattern. Understanding this technique is essential for professional Rails development and contributes to the framework's expressive nature.