An object has a state and a behavior.

In a ruby application we have many objects ! As we often read, “Everything in Ruby is an Object”

Each object has its own state, hold in instance variables. Many objects share the same behavior, the same set of methods.


class Artist
  def initialize(name, genre)
    @name = name.capitalize
    @genre = genre
  end

  def introduce
    puts "I'm #{@name} and I sing #{@genre}"
  end
end

etta = Artist.new("etta james", "blues")

For example,

  • @name and @genre are the state of the object etta.
  • introduce is a behavior that can be shared with many other objects.

Classes

Every object knows its class, which means when we call an object, Ruby finds its class and then looks at the available methods for this class.

For example, why can we use capitalize on “norah jones”?

>> norah = "norah jones"
"norah jones"

>> norah.capitalize
"Norah jones"

>> norah.class
String < Object

Because norah belongs to the String class.

The String class has many available methods, including capitalize. So it is accessible.

Now if we try to do this

norah.frozen?
>> false

What happens ? Does fronzen? belong to the String class ?

The Ruby interpreter examines the inheritance hierarchy of the receiver (norah here) to find the method that will be executed.


>> String.superclass
=> Object

=> frozen? is not part of String methods, so Ruby goes to its parent, Object, and finds it !

schema

Singleton class

This is the perfect moment to jump to the Singleton class subject !

Ruby provides a way to define methods -the singleton methods- that are specific to one object. That is why it is called "Singleton" :) ("single")


Ruby automatically creates a class to hold just the singleton methods, the Singleton Class !

So for example, let’s define a method sing for norah.

>> norah = "norah jones"

>> def norah.sing
>> "Come Away With Me"
>> end

>> norah.sing
"Come Away With Me"

We open a singleton class of norah and define a sing method, only available to this specific object.

schema

If we try to call it on britney it does not work.

>> britney = "britney spears"

>> def norah.sing
>>	"Come Away With Me"
>> end

>> britney.sing
Traceback (most recent call last):
        2: from /Users/cco/.rvm/rubies/ruby-2.5.3/bin/irb:11:in '<main>'
        1: from (irb):8
NoMethodError (undefined method 'sing' for "britney spears":String)

Britney can’t sing !

By inspecting the singleton class, we can see that the original class is String.

>> norah.singleton_class.inspect
"#<Class:#<String:0x00007fa83012a4a0>>"

Another thing we can do with Singleton classes is to override instance methods. Going back to the Artist class, we had a method introduce

class Artist
  def initialize(name, genre)
    @name = name.capitalize
    @genre = genre
  end

  def introduce
    puts "I'm #{@name} and I sing #{@genre}"
  end
end

norah = Artist.new("norah jones", "jazz")
etta = Artist.new("etta james", "blues")

Now let’s define a singleton method introduce for norah.

def norah.introduce
  super
  "Come Away With Me"
end

>> norah.introduce
I'm Norah jones and I sing jazz
"Come Away With Me"

>> etta.introduce
I'm Etta james and I sing blue

The Singleton class arrives before the Artist class, so Ruby uses the introduce singleton method first, for norah.

schema

And this time, the original class is Artist.

norah.singleton_class.inspect
"#<Class:#<Artist:0x00007fa83305df38>>"

We can list to singleton methods for an object like so:

>> norah.singleton_methods
[
    [0] introduce() #<Artist:0x00007fa83305df38 @name="Norah jones", @genre="jazz">
]

>> etta.singleton_methods
[]

There are more advanced uses of Singleton Classes, but understanding these basics is important.

Updated: