Thursday: Class Definitions - Metaprogramming Ruby - Metaprogramming Ruby 2: Program Like the Ruby Pros (2014)

Metaprogramming Ruby 2: Program Like the Ruby Pros (2014)

Part 1. Metaprogramming Ruby

Chapter 5. Thursday: Class Definitions

As you know, writing object-oriented programs means spending a good chunk of your time defining classes. In Java and C#, defining a class is like making a deal between you and the compiler. You say, “Here’s how my objects are supposed to behave,” and the compiler replies, “Okay, they will.” Nothing really happens until you create an object of that class and then call that object’s methods.

In Ruby, class definitions are different. When you use the class keyword, you aren’t just dictating how objects will behave in the future. On the contrary, you’re actually running code.

If you buy into this notion—that a Ruby class definition is actually regular code that runs—you’ll be able to cast some powerful spells. Two such spells that you’ll learn about in this chapter are Class Macros (Class Macro) (methods that modify classes) and Around Aliases (Around Alias)(methods that wrap additional code around other methods). To help you make the most of these spells, this chapter also describes singleton classes, one of Ruby’s most elegant features. Singleton classes are an advanced topic, so understanding them will win you bragging rights among Ruby experts.

This chapter also comes with a couple of public service announcements. First, keep in mind that a class is just a souped-up module, so anything you learn about classes also applies to modules. Although I won’t repeat this PSA in every section of this chapter, remember that whenever you read about a “class definition,” you can also think to yourself “module definition.” Second, be prepared: this is probably the most advanced chapter in the entire book. Read through it, and you will be able to walk the darkest corners of the Ruby object model.

Class Definitions Demystified

Where you and Bill tread familiar ground: the Bookworm application and the Ruby object model.

You stumble sleepily into the office, craving your Thursday morning coffee, only to be ambushed by an excited Bill. “Hey!” he says. “Everyone likes the refactorings of Bookworm we did Monday, and the boss wants more. But before we start, let’s go over some theory about class definitions. We’ll begin where we left off Monday: in the Ruby object model.”

Inside Class Definitions

You probably think of a class definition as the place where you define methods. In fact, you can put any code you want in a class definition:

class MyClass

puts 'Hello'

end

<=

Hello

Class definitions also return the value of the last statement, just like methods and blocks do:

result = class MyClass

self

end

result # => MyClass

This last example emphasizes a compelling point that you might remember from The self Keyword: in a class (or module) definition, the class itself takes the role of the current object self. Classes and modules are just objects, so why couldn’t a class be self? Keep this point about class definitions and self in mind, because the concept will become useful a bit later.

While we’re on the topic of self, you can learn about a related concept: that of the current class.

The Current Class

As you know, wherever you are in a Ruby program, you always have a current object: self. Likewise, you always have a current class (or module). When you define a method, that method becomes an instance method of the current class.

Although you can get a reference to the current object through self, there’s no equivalent keyword to get a reference to the current class. However, in most situations it’s easy to keep track of the current class just by looking at the code. Here’s how:

· At the top level of your program, the current class is Object, the class of main. (That’s why, if you define a method at the top level, that method becomes an instance method of Object.)

· In a method, the current class is the class of the current object. (Try defining a method inside another method with def, and you’ll see that the new method is defined on the class of self. This information is probably going to win you some Ruby trivia contest.)

· When you open a class with the class keyword (or a module with the module keyword), that class becomes the current class.

This last case is probably the only one that you care about in practice. Indeed, you use it all the time when you open a class with the class keyword, and define methods in the class with def. However, the class keyword has a limitation: it needs the name of a class. Unfortunately, in some situations you may not know the name of the class that you want to open. For example, think of a method that takes a class and adds a new instance method to it:

def add_method_to(a_class)

# TODO: define method m() on a_class

end

How can you open the class if you don’t know its name? You need some way other than the class keyword to change the current class. Enter the class_eval method.

class_eval()

Module#class_eval (also known by its alternate name, module_eval) evaluates a block in the context of an existing class:

class_definitions/class_eval.rb

def add_method_to(a_class)

a_class.class_eval do

def m; 'Hello!'; end

end

end

add_method_to String

"abc".m # => "Hello!"

Module#class_eval is very different from BasicObject#instance_eval, which you learned about earlier in instance_eval(). instance_eval only changes self, while class_eval changes both self and the current class.

(This is not the whole truth: instance_eval also changes the current class, but you’ll have to wait for Singleton Classes and instance_eval(), to learn how exactly. For now, you can safely ignore the problem and assume that instance_eval only changes self.)

By changing the current class, class_eval effectively reopens the class, just like the class keyword does.

Module#class_eval is actually more flexible than class. You can use class_eval on any variable that references the class, while class requires a constant. Also, class opens a new scope, losing sight of the current bindings, while class_eval has a Flat Scope (Flat Scope). As you learned in Scope Gates, this means you can reference variables from the outer scope in a class_eval block.

Finally, just like instance_eval has a twin method called instance_exec, module_eval/class_eval also has an equivalent module_exec/class_exec method that can pass extra parameters to the block.

Now that you know about both instance_eval and class_eval, you might wonder which of the two you should use. In most cases the answer is easy: you use instance_eval to open an object that is not a class, and class_eval to open a class definition and define methods with def. But what if you want to open an object that happens to be a class (or module) to do something other than using def? Should you use instance_eval or class_eval then?

If all you want is to change self, then both instance_eval and class_eval will do the job nicely. However, you should pick the method that best communicates your intentions. If you’re thinking, “I want to open this object, and I don’t particularly care that it’s a class,” then instance_eval is fine. If you’re thinking, “I want an Open Class (Open Class) here,” then class_eval is almost certainly a better match.

That was a lot of information about the current class and how to deal with it. Let’s recap the important points that we just went through.

Current Class Wrap-up

You learned a few things about class definitions:

· The Ruby interpreter always keeps a reference to the current class (or module). All methods defined with def become instance methods of the current class.

· In a class definition, the current object self and the current class are the same—the class being defined.

· If you have a reference to the class, you can open the class with class_eval (or module_eval).

How can this stuff ever be useful in real life? To show you how you can apply this theory about the current class, let’s look at a trick called Class Instance Variables.

Class Instance Variables

The Ruby interpreter assumes that all instance variables belong to the current object self. This is also true in a class definition:

class_definitions/class_instance_variables.rb

class MyClass

@my_var = 1

end

In a class definition, the role of self belongs to the class itself, so the instance variable @my_var belongs to the class. Don’t get confused. Instance variables of the class are different from instance variables of that class’s objects, as you can see in the following example:

class MyClass

@my_var = 1

def self.read; @my_var; end

def write; @my_var = 2; end

def read; @my_var; end

end

obj = MyClass.new

obj.read # => nil

obj.write

obj.read # => 2

MyClass.read # => 1

The previous code defines two instance variables. Both happen to be named @my_var, but they’re defined in different scopes, and they belong to different objects. To see how this works, you have to remember that classes are just objects, and you have to track self through the program. One@my_var is defined with obj as self, so it’s an instance variable of the obj object. The other @my_var is defined with MyClass as self, so it’s an instance variable of the MyClass object—a Spell: Class Instance Variable.

If you come from Java, you may be tempted to think that Class Instance Variables are similar to Java’s “static fields.” Instead, they’re just regular instance variables that happen to belong to an object of class Class. Because of that, a Class Instance Variable can be accessed only by the class itself—not by an instance or by a subclass.

We’ve touched on many things: the current class, class definitions, self, class_eval, Class Instance Variables.… Now you can go back to Bookworm and put these features together.

Class Variables

If you want to store a variable in a class, you have more options than just using a Class Instance Variable (Class Instance Variable). You can also use a class variable, identified by an @@ prefix:

class C

@@v = 1

end

Class variables are different from Class Instance Variables because they can be accessed by subclasses and by regular instance methods. (In that respect, they’re more similar to Java’s static fields.)

class D < C

def my_method; @@v; end

end

D.new.my_method # => 1

Unfortunately, class variables have a nasty habit of surprising you. Here’s an example:

@@v = 1

class MyClass

@@v = 2

end

@@v # => 2

You get this result because class variables don’t really belong to classes—they belong to class hierarchies. Because @@v is defined in the context of main, it belongs to main’s class Object…and to all the descendants of Object. MyClass inherits from Object, so it ends up sharing the same class variable. As technically sound as this behavior is, it’s still likely to trip you.

Because of unwelcome surprises like the one shown earlier, most Rubyists nowadays shun class variables in favor of Class Instance Variables. Also, Ruby 2.x issues a stern warning whenever you access a class variable from the top level.

Working on Bookworm Again

The Bookworm source contains very few unit tests, so it’s up to you and Bill to write tests as you refactor. Sometimes this proves to be difficult, as is the case with this class:

class_definitions/bookworm_classvars.rb

class Loan

def initialize(book)

@book = book

@time = Time.now

end

def to_s

"#{@book.upcase} loaned on #{@time}"

end

end

Loan stores the title of a book and the time when it was loaned—that is, the time when the object was created. You’d like to write a unit test for the to_s method, but to write that test, you’d have to know the exact time when the object was created. This is a common problem with code that relies on Time or Date: such code returns a different result every time it runs, so you don’t know what result to test for.

“I think I have a solution to this problem,” Bill announces. “It’s a bit involved, so it will require some attention on your part. Here it is.”

class Loan

def initialize(book)

@book = book

*

@time = Loan.time_class.now

end

*

def self.time_class

*

@time_class || Time

*

end

def to_s

# ...

Loan.time_class returns a class, and Loan#initialize uses that class to get the current time. The class is stored in a Class Instance Variable (Class Instance Variable) named @time_class. If @time_class is nil, the Nil Guard (Nil Guard) in time_class returns the Time class as a default.

In production, Loan always uses the Time class, because @time_class is always nil. By contrast, the unit tests can rely on a fake time class that always returns the same value. The tests can assign a value to the private @time_class variable by using either class_eval or instance_eval. Either of the two methods will do here, because they both change self:

class FakeTime

def self.now; 'Mon Apr 06 12:15:50'; end

end

require 'test/unit'

class TestLoan < Test::Unit::TestCase

def test_conversion_to_string

Loan.instance_eval { @time_class = FakeTime }

loan = Loan.new('War and Peace')

assert_equal 'WAR AND PEACE loaned on Mon Apr 06 12:15:50', loan.to_s

end

end

Bill is quite proud of his own coding prowess. He says, “I think we deserve a break—after I give you a quiz.”

Quiz: Class Taboo

Where you write an entire program without ever using a certain popular keyword.

Did you ever play Taboo?[8] The rules are simple: you’re given a secret word and a list of words that you cannot use. (They are “taboo.”) You must help a teammate guess the secret word. You can give your teammate as many suggestions as you want, but you must never say a taboo word. If you do that, you lose immediately.

Your challenge: play Taboo with Ruby code. You have only one taboo word, the class keyword. Your “secret word” is actually a Ruby class:

class MyClass < Array

def my_method

'Hello!'

end

end

You have to write a piece of code that has exactly the same effect as the previous one, without ever using the class keyword. Are you up to the challenge? (Just one hint: look at the documentation for Class.new.)

Quiz Solution

Because a class is just an instance of Class, you can create it by calling Class.new. Class.new also accepts an argument (the superclass of the new class) and a block that is evaluated in the context of the newborn class:

c = Class.new(Array) do

def my_method

'Hello!'

end

end

Now you have a variable that references a class, but the class is still anonymous. Do you remember the discussion about class names in Constants? The name of a class is just a constant, so you can assign it yourself:

MyClass = c

Interestingly, Ruby is cheating a little here. When you assign an anonymous class to a constant, Ruby understands that you’re trying to give a name to the class, and it does something special: it turns around to the class and says, “Here’s your new name.” Now the constant references the Class, and the Class also references the constant. If it weren’t for this trick, a class wouldn’t be able to know its own name, and you couldn’t write this:

c.name # => "MyClass"

You turn to Bill to show him your solution to the quiz—but he’s already busy browsing the Bookworm source. It’s time to get back to the task at hand.

Singleton Methods

Where it’s your turn to teach Bill a few tricks.

It’s late morning, and you and Bill are deep in the flow. You’re zipping through the Bookworm source, deleting a useless line here, changing a confusing name there, and generally polishing the code…until you bump into a particularly troublesome bit of refactoring.

The Paragraph class wraps a string and then delegates all calls to the wrapped string—all of them, that is, except for one method, Paragraph#title?, which returns true if a Paragraph is all uppercase.

class_definitions/paragraph.rb

class Paragraph

def initialize(text)

@text = text

end

def title?; @text.upcase == @text; end

def reverse; @text.reverse; end

def upcase; @text.upcase; end

# ...

Paragraph objects are created in a single place in the Bookworm source code. Also, Paragraph#title? is called only once in the whole application, from a method named index:

def index(paragraph)

add_to_index(paragraph) if paragraph.title?

end

Bill frowns. “The stupid Paragraph class really doesn’t hold its own weight. We could scrap it entirely and just use regular Strings, if it weren’t for the title? method.”

“Why don’t we Monkeypatch (Monkeypatch) the String class and add the title? method right there?” you offer. “I’m not convinced,” Bill says. “A method with that name would make sense only on strings that represent a paragraph, not on each and every string.”

While Bill is pondering the idea of patching the String class with a Refinement (Refinement), you decide to Google for a solution.

Introducing Singleton Methods

As it turns out, Ruby allows you to add a method to a single object. For example, here’s how you can add title? to a specific string:

class_definitions/singleton_methods.rb

str = "just a regular string"

def str.title?

self.upcase == self

end

str.title? # => false

str.methods.grep(/title?/) # => [:title?]

str.singleton_methods # => [:title?]

The previous code adds a method named title? to str. No other object gets the method—not even other Strings. A method like this one, which is specific to a single object, is called a Spell: Singleton Method. You can define a Singleton Method with either the syntax above or theObject#define_singleton_method method.

Thanks to Singleton Methods, you can now fix your problem with the Bookworm source. You can send any old String to index if you enhance that String with a title? Singleton Method:

class_definitions/paragraph.rb

paragraph = "any string can be a paragraph"

def paragraph.title?

self.upcase == self

end

index(paragraph)

Now you can use plain strings in Bookworm and delete the Paragraph class.

Bill is awestruck by your solution. “I knew about Singleton Methods, but I never realized you could use them this way.”

“Wait a minute,” you reply. “You knew about them? What did you think they were useful for?”

“Singleton Methods aren’t just useful for enhancing a specific object, like you just did.” Bill replies. “They’re also the basis for one of Ruby’s most common features. What if I told you that you’ve been using Singleton Methods all along, without ever knowing it?”

Duck Typing

Some people are horrified by Singleton Methods (Singleton Method), thinking that if each object can have its own methods, no matter which class it belongs to, then your code is going to become a twisted tangle of spaghetti.

If you reacted that way yourself, then you’re probably used to static languages. In a static language such as Java, you say that an object has type T because it belongs to class T (or because it implements interface T). In a dynamic language such as Ruby, the “type” of an object is not strictly related to its class. Instead, the “type” is simply the set of methods to which an object can respond.

People refer to this second, more fluid notion of a type as duck typing, referring to the saying: “if it walks like a duck and quacks like a duck, then it must be a duck.” In other words, you don’t care that an object is an instance of class Duck. You just care that it responds to walk and quack, whether they’re regular methods, Singleton Methods (Singleton Method), or even Ghost Methods (Ghost Method).

If you hang around Ruby for a while, you will get used to duck typing—and after learning a few cool dynamic tricks, you might even wonder how you could have lived without it in the first place.

The Truth About Class Methods

Remember what you learned in Inside the Object Model? Classes are just objects, and class names are just constants. If you remember this concept, then you’ll see that calling a method on a class is the same as calling a method on an object:

an_object.a_method

AClass.a_class_method

See? The first line calls a method on an object referenced by a variable, and the second line calls a method on an object (that also happens to be a class) referenced by a constant. It’s the same syntax.

But, wait—there’s more. Remember how Bill told you that you’ve been using Singleton Methods (Singleton Method) all along? That’s really what class methods are: they’re Singleton Methods of a class. In fact, if you compare the definition of a Singleton Method and the definition of a class method, you’ll see that they’re the same:

def obj.a_singleton_method; end

def MyClass.another_class_method; end

So, the syntax for defining a Singleton Method with def is always the same:

def object.method

# Method body here

end

In the definition shown previously, object can be an object reference, a constant class name, or self. The syntax might look different in the three cases, but in truth the underlying mechanism is always the same. Nice design, don’t you think?

You’re not quite finished with class methods yet. There’s a very useful and common spell that relies on class methods exclusively, and it deserves its own discussion.

Class Macros

Look at this example, coming straight from the core of Ruby.

The attr_accessor() Example

Ruby objects don’t have attributes. If you want something that looks like an attribute, you have to define two Mimic Methods (Mimic Method), a reader and a writer:

class_definitions/attr.rb

class MyClass

def my_attribute=(value)

@my_attribute = value

end

def my_attribute

@my_attribute

end

end

obj = MyClass.new

obj.my_attribute = 'x'

obj.my_attribute # => "x"

Writing methods like these (also called accessors) gets boring quickly. As an alternative, you can generate accessors by using one of the methods in the Module#attr_* family. Module#attr_reader generates the reader, Module#attr_writer generates the writer, and Module#attr_accessorgenerates both:

class MyClass

attr_accessor :my_attribute

end

All the attr_* methods are defined on class Module, so you can use them whenever self is a module or a class. A method such as attr_accessor is called a Spell: Class Macro. Class Macros look like keywords, but they’re just regular class methods that are meant to be used in a class definition.

“Now that you know about Class Macros,” Bill says, “I think I know a place in Bookworm’s source code where we can make good use of them.”

Class Macros Applied

The Book class in the Bookworm source code has methods named GetTitle, title2, and LEND_TO_USER. By Ruby’s conventions, these methods should be named title, subtitle, and lend_to, respectively. However, there are other projects that use the Book class, and you have no control over these projects. If you just rename the methods, you will break the callers.

Bill has an idea to fix this situation: you can rename the methods if you invent a Class Macro (Class Macro) that deprecates the old names:

class_definitions/deprecated.rb

class Book

def title # ...

def subtitle # ...

def lend_to(user)

puts "Lending to #{user}"

# ...

end

def self.deprecate(old_method, new_method)

define_method(old_method) do |*args, &block|

warn "Warning: #{old_method}() is deprecated. Use #{new_method}()."

send(new_method, *args, &block)

end

end

deprecate :GetTitle, :title

deprecate :LEND_TO_USER, :lend_to

deprecate :title2, :subtitle

end

The deprecate method takes the old name and the new name of a method and defines a Dynamic Method (Dynamic Method) that catches calls to the old name. The Dynamic Method forwards the calls to the renamed method—but first it prints a warning on the console to notify the callers that the old name has been deprecated:

b = Book.new

b.LEND_TO_USER("Bill")

<=

Warning: LEND_TO_USER() is deprecated. Use lend_to().

Lending to Bill

That was an ingenious way to use a Class Macro. However, if you really want to understand Class Macros, as well as Singleton Methods in general, you have to fit one last missing piece in the Ruby object model.

Singleton Classes

Where you place the final piece in the object model puzzle.

Singleton classes are the UFOs of the Ruby world: even if you never see one in person, you can find scattered hints of their existence all over the place. Let’s start our investigation into this difficult subject by collecting some evidence. (Be aware that the next few pages contain advanced material that might take a while for you to digest. If you want, you can skip straight to Method Wrappers, on your first read through and come back to this section later.)

The Mystery of Singleton Methods

In Method Lookup, you learned how Ruby finds methods by going right into the receiver’s class and then up the class hierarchy. For example:

class MyClass

def my_method; end

end

obj = MyClass.new

obj.my_method

Bill draws the following flowchart and says, “When you call my_method, Ruby goes right into MyClass and finds the method there.” So far, so good.

images/chp4_object_lookup.jpg

Now, what happens if you define a Singleton Method (Singleton Method) on obj?

def obj.my_singleton_method; end

If you look at the previous flowchart, you’ll notice that there’s no obvious home for my_singleton_method there.

The Singleton Method can’t live in obj, because obj is not a class. It can’t live in MyClass, because if it did, all instances of MyClass would share it. And it cannot be an instance method of MyClass’s superclass, Object. So then, where do Singleton Methods live?

Class methods are a special kind of Singleton Method—and just as baffling:

def MyClass.my_class_method; end

If you look at the following figure, you’ll find that, again, my_class_method doesn’t seem to live anywhere in Bill’s diagram.

images/chp4_class_lookup.jpg

The explanation of this mystery could surprise you.

Singleton Classes Revealed

When you ask an object for its class, Ruby doesn’t always tell you the whole truth. Instead of the class that you see, an object can have its own special, hidden class. That’s called the singleton class of the object. (You can also hear it called the metaclass or the eigenclass. However, “singleton class” is the official name.)

Methods like Object#class keep the singleton class carefully hidden, but you can work around them. Ruby has a special syntax, based on the class keyword, that places you in the scope of the singleton class:

class << an_object

# your code here

end

If you want to get a reference to the singleton class, you can return self out of the scope:

obj = Object.new

singleton_class = class << obj

self

end

singleton_class.class # => Class

That sneaky singleton class was trying to hide, but we managed to find it.

Back in Ruby’s old days, you had to return self like we just did to get a reference to the singleton class. These days you can also get a reference to the singleton class with the handy Object#singleton_class method:

"abc".singleton_class # => #<Class:#<String:0x331df0>>

The previous example also shows that a singleton class is a class—but a very special one. For starters, it’s invisible until you resort to either Object#singleton_class, or the exotic class << syntax. Also, singleton classes have only a single instance (that’s where their name comes from), and they can’t be inherited. More important, a singleton class is where an object’s Singleton Methods live:

def obj.my_singleton_method; end

singleton_class.instance_methods.grep(/my_/) # => [:my_singleton_method]

To fully understand the consequences of this last point, you have to look deeper into Ruby’s object model.

Method Lookup Revisited

In What Happens When You Call a Method?, you learned about the Ruby object model and method lookup. Back then, we had to leave some parts of the object model unexplored. Singleton classes are the missing link we needed. Once you understand singleton classes, all the bits and pieces in the object model finally fall into place.

Method Lookup Review

To look into the object model, you need a practical example to focus on. Let’s write a “lab rat” program:

class C

def a_method

'C#a_method()'

end

end

class D < C; end

obj = D.new

obj.a_method # => "C#a_method()"

If you draw a picture of obj and its ancestors chain, it will probably look like the following figure. (For now, you don’t have to bother with singleton classes or modules.)

images/chp4_lookup_simple.jpg

You know that method lookup goes one step to the right, then up. When you call obj.a_method(), Ruby goes right into obj’s class D. From there, it climbs up the ancestors chain until it finds a_method in class C. Now, let’s add singleton classes to the mix.

Singleton Classes and Method Lookup

As you explore singleton classes, you may notice that their names are not meant to be uttered by humans. When you print it on the screen, a singleton class looks something like this:

obj = Object.new

obj.singleton_class # => #<Class:#<Object:0x007fd96909b588>>

The diagrams in the rest of this chapter identify singleton classes with a simple # prefix. By this convention, #obj is the singleton class of obj, #C is the singleton class of C, and so on.

Armed with the singleton_class method and your new naming convention, you can now proceed with your fearless exploration of the object model. Let’s go back to the “lab rat” program and define a Singleton Method (Singleton Method).

class << obj

def a_singleton_method

'obj#a_singleton_method()'

end

end

Now for an experiment. You know that a singleton class is a class, so it must have a superclass. Which is the superclass of the singleton class?

obj.singleton_class.superclass # => D

The superclass of obj’s singleton class is D. Try adding this newfound knowledge to the diagram of the “lab rat” object model. The result is shown in Figure 7, Method lookup with singleton classes.

images/chp4_lookup_eigen.jpg


Figure 7. Method lookup with singleton classes

You can see how Singleton Methods fit into the normal process of method lookup. If an object has a singleton class, Ruby starts looking for methods in the singleton class rather than the conventional class, and that’s why you can call Singleton Methods such as obj#a_singleton_method. If Ruby can’t find the method in the singleton class, then it goes up the ancestors chain, ending in the superclass of the singleton class—which is the object’s class. From there, everything is business as usual.

Now you understand how Singleton Methods work. But what about class methods? Yes, they’re just a special case of Singleton Methods, but they deserve a closer look.

Singleton Classes and Inheritance

In this section, we’re going to look at the connections between classes, singleton classes, and superclasses. This area of the object model can be a real brain-twister. Once it clicks in your mind, however, it will feel elegant and beautiful. If you’re stuck, just look at the pictures or fire up irb and experiment on your own.

Try adding a class method to the “lab rat” program.

class C

class << self

def a_class_method

'C.a_class_method()'

end

end

end

Now you can explore the resulting object model. (As you do that, keep in mind that singleton classes became slightly more visible in Ruby 2.1. Starting from that version, if you ask a singleton class for its ancestors, the result will include ancestors that are themselves singleton classes. Until Ruby 2.0, ancestors always shows regular classes only.)

C.singleton_class # => #<Class:C>

D.singleton_class # => #<Class:D>

D.singleton_class.superclass # => #<Class:C>

C.singleton_class.superclass # => #<Class:Object>

Bill grabs a scrap of paper and draws the following diagram.

images/chp4_lookup_inheritance.jpg


Figure 8. Singleton classes and inheritance

This is a somewhat complicated diagram. The arrows marked with S link classes to their superclasses, and the arrows marked with C link objects (including classes) to their classes, which in this case are all singleton classes. The arrows marked with a C do not point at the same classes that the class method would return, because the class method doesn’t know about singleton classes. For example, obj.class would return D, even if the class of obj is actually its singleton class, #obj.

Meta Squared

Singleton classes are classes, and classes are objects, and objects have singleton classes…. Can you see where this train of thought is going? Like any other object, a singleton class must have its own singleton class:

class << "abc"

class << self

self # => #<Class:#<Class:#<String:0x33552c>>>

end

end

If you ever find a practical use for singleton classes of singleton classes, let the world know.

This diagram doesn’t include modules. If you’re a completist, you can draw the Kernel module between Object and BasicObject. On the other hand, you probably don’t want to include #Kernel in this diagram. Although modules can have singleton classes like any other object, the singleton class of Kernel is not part of obj’s or #D’s ancestor chains.

Apparently, Ruby organizes classes, singleton classes, and superclasses in a very purposeful pattern. The superclass of #D is #C, which is also the singleton class of C. By the same rule, the superclass of #C is #Object. Bill tries to sum it all up, making things even more confusing: “The superclass of the singleton class is the singleton class of the superclass. It’s easy.”

This complicated arrangement of classes, superclasses, and singleton classes can be baffling. Why does Ruby go to such lengths to organize the object model this way? The reason is that thanks to this arrangement, you can call a class method on a subclass:

D.a_class_method # => "C.a_class_method()"

Even if a_class_method is defined on C, you can also call it on D. This is probably what you expect, but it’s only possible because method lookup starts in #D and goes up to #D’s superclass #C, where it finds the method.

Ingenious, isn’t it? Now you can finally grasp the entire object model.

The Great Unified Theory

“The Ruby object model is a beautiful place,” Bill notes, with a dreamy expression on his face. “There are classes, singleton classes, and modules. There are instance methods, class methods, and Singleton Methods.”

At first glance, it all looks very complex. Look closer, and the complexity fades away. If you put singleton classes together with regular classes and modules, you end up with the seven rules of the Ruby object model:

1. There is only one kind of object—be it a regular object or a module.

2. There is only one kind of module—be it a regular module, a class, or a singleton class.

3. There is only one kind of method, and it lives in a module—most often in a class.

4. Every object, classes included, has its own “real class,” be it a regular class or a singleton class.

5. Every class, with the exception of BasicObject, has exactly one ancestor—either a superclass or a module. This means you have a single chain of ancestors from any class up to BasicObject.

6. The superclass of the singleton class of an object is the object’s class. The superclass of the singleton class of a class is the singleton class of the class’s superclass. (Try repeating that three times, fast. Then look back at Figure 8, Singleton classes and inheritance, and it will all make sense.)

7. When you call a method, Ruby goes “right” in the receiver’s real class and then “up” the ancestors chain. That’s all there is to know about the way Ruby finds methods.

Any Ruby programmer can stumble on a difficult question about the object model. “Which method in this complicated hierarchy gets called first?” Or maybe, “Can I call this method from that object?” When this happens to you, review the seven rules listed earlier, maybe draw a quick diagram of the object model, and you’ll find the answer in no time at all.

Congratulations—you now understand the entire Ruby object model.

Class Methods Syntaxes

Because class methods are just Singleton Methods that live in the class’s singleton class, now you have three different ways to define a class method. They’re shown in the following code.

def MyClass.a_class_method; end

class MyClass

def self.another_class_method; end

end

class MyClass

class << self

def yet_another_class_method; end

end

end

The first syntax is usually frowned upon by expert Rubyists because it duplicates the class name, making it more difficult to refactor. The second syntax takes advantage of the fact that self in the class definition is the class itself. The third syntax is the trickiest one: the code opens the singleton class and defines the method in there. This last syntax acknowledges the singleton class explicitly, so it will win you some street cred in Ruby circles.

Singleton Classes and instance_eval()

Now that you know about singleton classes, you can also fill in one missing snippet of knowledge about the instance_eval method. In class_eval(), you learned that instance_eval changes self, and class_eval changes both self and the current class. However, instance_eval also changes the current class; it changes it to the singleton class of the receiver. This example uses instance_eval to define a Singleton Method (Singleton Method):

class_definitions/instance_eval.rb

s1, s2 = "abc", "def"

s1.instance_eval do

def swoosh!; reverse; end

end

s1.swoosh! # => "cba"

s2.respond_to?(:swoosh!) # => false

You’ll rarely, if ever, see instance_eval used purposefully to change the current class, as in the example above. The standard meaning of instance_eval is this: “I want to change self.”

Class Attributes

Bill’s detailed explanations have left you a bit perplexed. “Okay,” you say, “I can see how singleton classes are useful to understanding the object model. But how do I use them in practice?”

Let’s look at an example involving Class Macros (Class Macro). Do you remember the attr_accessor method from The attr_accessor() Example? It generates attributes for any object:

class_definitions/class_attr.rb

class MyClass

attr_accessor :a

end

obj = MyClass.new

obj.a = 2

obj.a # => 2

But what if you want to define an attribute on a class instead? You might be tempted to reopen Class and define the attribute there:

class MyClass; end

class Class

attr_accessor :b

end

MyClass.b = 42

MyClass.b # => 42

This works, but it adds the attribute to all classes. If you want an attribute that’s specific to MyClass, you need a different technique. Define the attribute in the singleton class:

class MyClass

class << self

attr_accessor :c

end

end

MyClass.c = 'It works!'

MyClass.c # => "It works!"

To understand how this works, remember that an attribute is actually a pair of methods. If you define those methods in the singleton class, they become class methods, as if you’d written this:

def MyClass.c=(value)

@c = value

end

def MyClass.c

@c

end

As usual, Bill grabs the nearest available scrap of paper and scribbles the following diagram on it. “That’s how you define an attribute on a class,” he says.

images/chp4_class_attributes.jpg


Figure 9. Class attributes live in the class’s singleton class.

You can also see another interesting detail in this diagram. The superclass of #BasicObject is none other than good old Class. This fact explains why you can call MyClass.b and MyClass.b=.

Clearly happy with his own explanation, Bill leans back in his comfy chair. “Cool stuff, huh? Now, let’s try a little quiz.”

Quiz: Module Trouble

Where you learn that singleton classes and modules mix well with each other.

Bill decides it’s time for a story: “Every single day, somewhere in the world, a Ruby programmer tries to define a class method by including a module. I tried it myself, but it didn’t work.”

class_definitions/module_trouble_failure.rb

module MyModule

def self.my_method; 'hello'; end

end

class MyClass

include MyModule

end

MyClass.my_method # NoMethodError!

“You see,” Bill continues, “when a class includes a module, it gets the module’s instance methods—not the class methods. Class methods stay out of reach, in the module’s singleton class.”

“So, how did you find a solution?” you ask. “Oh, I didn’t,” Bill replies, blushing. “I just asked for the solution on a mailing list, like everybody else does. But maybe you can find a solution.” Think about the object model and singleton classes. How would you modify the code that you just looked at so that it works as expected?

Quiz Solution

The solution to this quiz is simple and subtle at the same time. First, define my_method as a regular instance method of MyModule. Then include the module in the singleton class of MyClass.

class_definitions/module_trouble_solution.rb

module MyModule

*

def my_method; 'hello'; end

end

class MyClass

*

class << self

*

include MyModule

*

end

end

MyClass.my_method # => "hello"

my_method is an instance method of the singleton class of MyClass. As such, my_method is also a class method of MyClass. This technique is called a Spell: Class Extension.

“That’s brilliant,” Bill says. “What about trying the same trick on a regular object instead of a class?”

Class Methods and include()

Reviewing Class Extensions, you can define class methods by mixing them into the class’s singleton class. Class methods are just a special case of Singleton Methods, so you can generalize this trick to any object. In the general case, this is called an Spell: Object Extension. In the following example, obj is extended with the instance methods of MyModule:

class_definitions/module_trouble_object.rb

module MyModule

def my_method; 'hello'; end

end

obj = Object.new

class << obj

include MyModule

end

obj.my_method # => "hello"

obj.singleton_methods # => [:my_method]

In case you think that opening the singleton class is a clumsy way to extend a class or an object, let’s also look at an alternative technique.

Object#extend

Class Extensions (Class Extension) and Object Extensions (Object Extension) are common enough that Ruby provides a method just for them, named Object#extend:

class_definitions/module_trouble_extend.rb

module MyModule

def my_method; 'hello'; end

end

obj = Object.new

obj.extend MyModule

obj.my_method # => "hello"

class MyClass

extend MyModule

end

MyClass.my_method # => "hello"

Object#extend is simply a shortcut that includes a module in the receiver’s singleton class. You can always do that yourself, if you so choose.

“Enough talking about singleton classes today,” Bill announces. “I don’t want to get a meta-headache. For now, let’s go back to refactoring Bookworm.”

Method Wrappers

Where you learn how to wrap a method inside another method—three different ways.

As the day draws to a close, you and Bill find yourselves stuck. Many methods in Bookworm rely on an open source library that retrieves a book’s reviews from Amazon’s website. The following code shows one example:

def deserves_a_look?(book)

amazon = Amazon.new

amazon.reviews_of(book).size > 20

end

This code works in most cases, but it doesn’t manage exceptions. If a remote call to Amazon fails, Bookworm itself should log this problem and proceed. You could easily add exception management to each line in Bookworm that calls deserves_a_look?—but there are tens of such lines, and you don’t want to change all of them.

To sum up the problem: you have a method that you don’t want to modify directly because it’s in a library. You want to wrap additional functionality around this method so that all clients get the additional functionality automatically. You can do this in a few ways, but to get to the first of them you need to know about aliases.

Around Aliases

You can give an alternate name to a Ruby method by using Module#alias_method:

class_definitions/alias.rb

class MyClass

def my_method; 'my_method()'; end

alias_method :m, :my_method

end

obj = MyClass.new

obj.my_method # => "my_method()"

obj.m # => "my_method()"

In alias_method, the new name for the method comes first, and the original name comes second. You can provide the names either as symbols or as strings.

(Ruby also has an alias keyword, which is an alternative to Module#alias_method. It can be useful if you want to alias a method at the top level, where Module#alias_method is not available.)

Continuing with the previous example:

class MyClass

alias_method :m2, :m

end

obj.m2 # => "my_method()"

Aliases are common everywhere in Ruby, including the core libraries. For example, String#size is an alias of String#length, and the Integer class has a method with no fewer than five different names. (Can you spot it?)

What happens if you alias a method and then redefine it? You can try this with a simple program:

class_definitions/wrapper_around_alias.rb

class String

alias_method :real_length, :length

def length

real_length > 5 ? 'long' : 'short'

end

end

"War and Peace".length # => "long"

"War and Peace".real_length # => 13

The previous code redefines String#length, but the alias still refers to the original method. This gives you insight into how method redefinition works. When you redefine a method, you don’t really change the method. Instead, you define a new method and attach an existing name to that new method. You can still call the old version of the method as long as you have another name that’s still attached to it.

This idea of aliasing a method and then redefining it is the basis of an interesting trick—one that deserves its own example.

The Thor Example

Thor is a Ruby gem for building command-line utilities. Some versions of Thor include a program named rake2thor that converts Rake build files to Thor scripts. As part of doing that, rake2thor must load a Rakefile and store away the names of all the files that are in turn required from that Rakefile. Here is the code where the magic happens:

gems/thor-0.17.0/bin/rake2thor

input = ARGV[0] || 'Rakefile'

$requires = []

module Kernel

def require_with_record(file)

$requires << file if caller[1] =~ /rake2thor:/

require_without_record file

end

alias_method :require_without_record, :require

alias_method :require, :require_with_record

end

load input

The code above prepares a global array to store the names of the required files; then it opens the Kernel module and plays a few tricks with method aliases; and finally, it loads the Rakefile. Focus on the middle part—the code dealing with Kernel. To understand what is going on there, look at this slightly simplified version of the original code:

module Kernel

alias_method :require_without_record, :require

def require(file)

$requires << file if caller[1] =~ /rake2thor:/

require_without_record file

end

end

The Open Class (Open Class) above does three things. First, it aliases the standard Kernel#require method to another name (require_without_record). Second, it Monkeypatches (Monkeypatch) require to store the names of files that are required by the Rakefile. (It does that by getting the stack of callers with the Kernel#callers method. If the second caller in the stack is rake2thor itself, this means that the Rakefile must be the first caller in the stack—the one that actually called require.) Finally, the new require falls back to the original require, now called require_without_record.

Compared to this simplified version, the original rake2thor code goes one step further: it also creates an alias for the new require called require_with_record. While this latest alias makes the methods more explicit, the important result is pretty much the same in both versions of the code:Kernel#require has changed, and the new require is “wrapped around” the old require. That’s why this trick is called an Spell: Around Alias.

You can write an Around Alias in three simple steps:

1. You alias a method.

2. You redefine it.

3. You call the old method from the new method.

One downside of Around Aliases is that they pollute your classes with one additional method name. You can fix this small problem somehow by making the old version of the method private after you alias it. (In Ruby it’s the method’s name, not the method itself, that is either public or private.)

Another potential problem of Around Aliases has to do with loading. You should never load an Around Alias twice, unless you want to end up with an exception when you call the method. Can you see why?

The main issue with Around Aliases, however, is that they are a form of Monkeypatching. Like all Monkeypatches, they can break existing code that wasn’t expecting the method to change. For this reason, Ruby 2.0 introduced not one, but two additional ways to wrap additional functionality around an existing method.

More Method Wrappers

In Refinements, you learned that a Refinement (Refinement) works like a patch of code that has been slapped directly over a class. However, Refinements have one additional feature that enables you to use them in place of Around Aliases (Around Alias): if you call super from a refined method, you will call the original, unrefined method. Here comes an example:

class_definitions/wrapper_refinement.rb

module StringRefinement

refine String do

def length

super > 5 ? 'long' : 'short'

end

end

end

using StringRefinement

"War and Peace".length # => "long"

The code above refines the String class to wrap additional functionality around its length method. Like other Refinements, this Spell: Refinement Wrapper applies only until the end of the file (or, in Ruby 2.1, the module definition). This makes it generally safer than the equivalent Around Alias, which applies everywhere.

Finally, you have a third way of wrapping a method: you can use Module#prepend, which you might remember from Modules and Lookup. Module#prepend works a bit like include, but it inserts the module below the includer in the chain of ancestors, rather than above it. This means that a method in a prepended module can override a method in the includer and call the non-overridden version with super:

class_definitions/wrapper_prepend.rb

module ExplicitString

def length

super > 5 ? 'long' : 'short'

end

end

String.class_eval do

prepend ExplicitString

end

"War and Peace".length # => "long"

You can call this a Spell: Prepended Wrapper. It’s not local like a Refinement Wrapper, but it’s generally considered cleaner and more explicit than both a Refinement Wrapper and an Around Alias.

Now you know more than enough to get back to the Bookworm source code.

Solving the Amazon Problem

Remember where this discussion of method wrappers originated? You and Bill wanted to wrap logging and exception handling around the Amazon#reviews_of method. Now you can finally do that with an Around Alias (Around Alias), a Refinement Wrapper (Refinement Wrapper), or aPrepended Wrapper (Prepended Wrapper). The third option looks cleaner, as it doesn’t dabble in Monkeypatching or weird Refinement rules:

class_definitions/bookworm_wrapper.rb

module AmazonWrapper

def reviews_of(book)

start = Time.now

result = super

time_taken = Time.now - start

puts "reviews_of() took more than #{time_taken} seconds" if time_taken > 2

result

rescue

puts "reviews_of() failed"

[]

end

end

Amazon.class_eval do

prepend AmazonWrapper

end

As you admire this smart piece of code, Bill hits you with an unexpected quiz.

Quiz: Broken Math

Where you find that one plus one doesn’t always equal two.

Most Ruby operators are actually methods. For example, the + operator on integers is syntactic sugar for a method named Fixnum#+. When you write 1 + 1, the parser internally converts it to 1.+(1).

The cool thing about methods is that you can redefine them. So, here’s your challenge: break the rules of math by redefining Fixnum#+ so that it always returns the correct result plus one. For example:

1 + 1 # => 3

Quiz Solution

You can solve this quiz with an Open Class (Open Class). Just reopen Fixnum and redefine + so that (x + y) becomes (x + y + 1). This is not as easy as it seems, however. The new version of + relies on the old version of +, so you need to wrap your old version with the new version. You can do that with an Around Alias (Around Alias):

class_definitions/broken_math.rb

class Fixnum

alias_method :old_plus, :+

def +(value)

self.old_plus(value).old_plus(1)

end

end

Now you have the power to wreak havoc on Ruby’s basic arithmetic. Enjoy this code responsibly.

Wrap-Up

You covered a lot of ground today. Let’s sum it all up:

· You looked at the effects of class definitions on self (the default receiver of the methods you call) and on the current class (the default home of the methods you define).

· You made acquaintance with Singleton Methods (Singleton Method) and singleton classes, gaining new insights into the object model and method lookup.

· You added a few new tricks to your bag, including Class Instance Variables (Class Instance Variable), Class Macros (Class Macro), and Prepended Wrappers (Prepended Wrapper).

Also remember that today you used the word “class” as a shortcut to “class or module,” and everything you learned about classes can also be applied to modules: the “current class” might actually be a module, a “class instance variable” could well be a “module instance variable,” and so on.

That was quite a deep dive into Ruby’s object model. As the two of you prepare to leave the office, Bill makes a promise that tomorrow will be less talking and more coding. “I’m really looking forward to that,” he says.

Footnotes

[8]

http://en.wikipedia.org/wiki/Taboo_(game).