2.5. Ruby is Object-Oriented

Ruby only knows objects. Everything is an object (sounds almost like Zen). Every object is an instance of a class. You can find out the class of an object via the method .class.
An object in Ruby is encapsulated and can only be reached from the outside via the methods of the corresponding object. What does this mean? I cannot change any property of an object directly from the outside. The corresponding object has to offer a method with which I can do so.

Note

Please do not panic if you have no idea what a class and an object is. I won't tell anyone and you can still work with it just fine without worrying too much. This topic alone could fill whole volumes. Roughly speaking, an object is a container for something and a method changes something in that container.
Please go on reading and have a look at the examples. The puzzle will gradually get clearer.
BTW: I will use variable in a couple of examples but will discuss variables in detail later (Section 2.6, “Variables”).

Methods

In other programming languages, the terms you would use for Ruby methods would be: functions, procedures, subroutines and of course methods.

Note

There are two kinds of methods (class methods and instance methods). At this point, I do not want to make it too complicated and am simply ignoring this "fine" distinction for now.
At this point you start looking for a good example, but all you can think of are silly ones. The problem is the premisse that we are only allowed to use knowledge that has already been described previously in this book.
So let's assume that we use the following code sequence repeatedly - for whatever reason:
$ irb --simple-prompt
>> puts 'Hello World!'
Hello World!
=> nil
>> puts 'Hello World!'
Hello World!
=> nil
>> puts 'Hello World!'
Hello World!
=> nil
>> exit
$
So we want to output the string Hello World! three times in a row. As this makes our daily work routine much longer, we are now going to define a method (with the meaningless name three_times), with which this can all be done in one go.

Important

Names of methods are always written in lower case.
$ irb --simple-prompt
>> def three_times
>>   puts 'Hello World!'
>>   puts 'Hello World!'
>>   puts 'Hello World!'
>> end
=> nil
>> three_times
Hello World!
Hello World!
Hello World!
=> nil
>> exit
$
When defining a method, you can define required parameters and use them within the method. This enables us to create a method to which we pass a string as parameter and we can then output it three times.
$ irb --simple-prompt
>> def three_times(value)
>>   puts value
>>   puts value
>>   puts value
>> end
=> nil
>> three_times('Hello World!')
Hello World!
Hello World!
Hello World!
=> nil
>>
Incidentally, you can omit the brackets when calling the method.
>> three_times 'Hello World!'
Hello World!
Hello World!
Hello World!
=> nil
>>

Tip

Ruby gurus and would-be gurus are going to turn up their noses on the subject of unnecessary brackets in your programs and will probably pepper you with more or less stupid comments with comparisons to Java and other programming languages.
There is one simple rule in the Ruby community: the fewer brackets, the cooler you are! ;-)
Between you and me: you won't get a medal for using fewer brackets. Decide for yourself what makes you happy.
If you do not specify a parameter with the above method, you will get the error message: wrong number of arguments (0 for 1):
>> three_times
ArgumentError: wrong number of arguments (0 for 1)
 from (irb):1:in `three_times'
 from (irb):7
 from /Users/xyz/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'
>> exit
$
You can give the variable value a default value and then you can also call the method without parameter:
$ irb --simple-prompt
>> def three_times(value = 'blue')
>>   puts value
>>   puts value
>>   puts value
>> end
=> nil
>> three_times('Hello World!')
Hello World!
Hello World!
Hello World!
=> nil
>> three_times
blue
blue
blue
=> nil
>> exit
$

Classes

A class is a collection of methods. The name of a class always starts with an upper case letter. Let's assume that the method belongs to the new class This_and_that. It would then be defined as follows in a Ruby program:
class This_and_that
  def three_times
    puts 'Hello World!'
    puts 'Hello World!'
    puts 'Hello World!'
  end
end
Let's play it through in irb:
$ irb --simple-prompt
>> class This_and_that
>>   def three_times
>>     puts 'Hello World!'
>>     puts 'Hello World!'
>>     puts 'Hello World!'
>>   end
>> end
=> nil
>>
Now we try to call the method three_times:
>> This_and_that.three_times
NoMethodError: undefined method `three_times' for This_and_that:Class
 from (irb):8
 from /Users/xyz/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'
>>
This results in an error message, because This_and_that is a class and not an instance. As we are working with instance methods, it only works if we have first created a new object (a new instance) of the class This_and_that with the class method new:
>> abc = This_and_that.new
=> #<This_and_that:0x007f819412c768>
>> abc.three_times
Hello World!
Hello World!
Hello World!
=> nil
>> exit
$
I will explain the difference between instance and class methods in more detail in the section called “Class Methods and Instance Methods”. Another chicken and egg problem.

Private Methods

Quite often it makes sense to only call a method within its own class or own instance. Such methods are referred to as private methods (as opposed to public methods), and they are listed below the keyword private within a class.
irb example:
$ irb --simple-prompt
>> class Example
>>   def a
>>     puts 'a'
>>   end
>>   private
>>   def b
>>     puts 'b'
>>   end
>> end
=> nil
>> test = Example.new
=> #<Example:0x007ff1e10756b8>
>> test.a
a
=> nil
>> test.b
NoMethodError: private method `b' called for #<Example:0x007ff1e10756b8>
 from (irb):12
 from /Users/xyz/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'
>> exit
$ 

Method initialize()

If a new instance is created (by calling the method new), the method that is processed first and automatically is the method initialize. The method is automatically a private method, even if it not listed explicitly under private.
irb example:
$ irb --simple-prompt
>> class Room
>>   def initialize
>>     puts 'abc'
>>   end
>> end
=> nil
>> kitchen = Room.new
abc
=> #<Room:0x007faec50402d8>
>> exit
$
The instance kitchen is created with Room.new and the method initialize is processed automatically.
The method new accepts the parameters specified for the method initialize:
$ irb --simple-prompt
>> class Example
>>   def initialize(value)
>>     puts value
>>   end
>> end
=> nil
>> test = Example.new('Hello World!')
Hello World!
=> #<Example:0x007fa9f98ba240>
>> exit
$

return

puts is nice to demonstrate an example in this book but normally you need a way to return the result of something. The return statement can be used for that:
$ irb --simple-prompt
>> def area_of_a_cirle(radius)
>>   pi = 3.14
>>   area = pi * radius * radius
>>   return area
>> end
=> nil
>> area_of_a_cirle(10)
=> 314.0
>> exit
$
But it wouldn't be Ruby if you couldn't do it shorter. You can simply skip return:
$ irb --simple-prompt
>> def area_of_a_cirle(radius)
>>   pi = 3.14
>>   area = pi * radius * radius
>>   area
>> end
=> nil
>> area_of_a_cirle(10)
=> 314.0
>> exit
$
You can actually even skip the last line because Ruby returns the value of the last expression as a default:
$ irb --simple-prompt
>> def area_of_a_cirle(radius)
>>   pi = 3.14
>>   area = pi * radius * radius
>> end
=> nil
>> area_of_a_cirle(10)
=> 314.0
>> exit
$ 
return is sometimes useful to make a method easier to read. But you don't have to use it in case you feel more comfortable with out.

Inheritance

A class can inherit from another class. When defining the class, the parent class must be added with a < (smaller than) sign:
class Example < ParentClass
Rails makes use of this approach very frequently (otherwise I would not be bothering you with it).
In the following example, we define the class Abc and which contains the methods a, b and c. Then we define a class Abcd and let it inherit the class Abc and add a new method d. The new instances example1 and example2 are created with the Class-Methods new and show that example2 has access to the methods a, b, c and d but example1 only to a, b and c.
$ irb --simple-prompt
>> class Abc
>>   def a
>>     'a'
>>   end
>>   def b
>>     'b'
>>   end
>>   def c
>>     'c'
>>   end
>> end
=> nil
>> class Abcd < Abc
>>   def d
>>     'd'
>>   end
>> end
=> nil
>> example1 = Abc.new
=> #<Abc:0x007fb463023928>
>> example2 = Abcd.new
=> #<Abcd:0x007fb46302f020>
>> example2.d
=> "d"
>> example2.a
=> "a"
>> example1.d
NoMethodError: undefined method `d' for #<Abc:0x007fb463023928>
 from (irb):21
 from /Users/xyz/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'
>> example1.a
=> "a"
>> exit
$ 

Tip

It is important to read the Error-Messages. They tell you what happend and where to search for the problem. In this example Ruby said that there is an undefined method `d' for #<Abc:0x007fb463023928>. With that information you know that the Class Abc is missing the method d which you were trying to use.

Class Methods and Instance Methods

There are two important kinds of methods: class methods and instance methods.
You now already know what a class it. And an instance of such a class is created via the class method new. A class method can only be called in connection with the class (for example, the method new is a class method). An instance method is a method that only works with an instance. So you cannot apply the method new to an instance.
Let's first try to call an instance method as class method:
$ irb --simple-prompt
>> class Knowledge
>>   def pi
>>     3.14
>>   end
>> end
=> nil
>> Knowledge.pi
NoMethodError: undefined method `pi' for Knowledge:Class
 from (irb):6
 from /Users/xyz/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'
>>
So that does not work. Well, then let's create a new instance of the class and try again:
>> example = Knowledge.new
=> #<Knowledge:0x007fd81b0866f0>
>> example.pi
=> 3.14
>> exit
$
Now we just need to find out how to define a class method. Hardcore Rails gurus would now whisk you away into the depths of the source code and pick out examples from the ActiveRecord. I will spare you this and show an abstract example:
$ irb --simple-prompt
>> class Knowledge
>>   def self.pi
>>     3.14
>>   end
>> end
=> nil
>> Knowledge.pi
=> 3.14
>>
And the proof to the contrary:
>> example = Knowledge.new
=> #<Knowledge:0x007fb339078d90>
>> example.pi
NoMethodError: undefined method `pi' for #<Knowledge:0x007fb339078d90>
 from (irb):8
 from /Users/xyz/.rvm/rubies/ruby-1.9.3-p327/bin/irb:16:in `<main>'
>> exit
$
There are different notations for defining class methods. The two most common ones are:
  • self.xyz
    # Variant 1
    # with self.xyz
    #
    class Knowledge
      def self.pi
        3.14
      end
    end
  • class << self
    # Variant 2
    # with class << self
    #
    class Knowledge
      class << self
        def pi
          3.14
        end
      end
    end
The result is always the same.
Of course you can use the same methodname for a class and an instance method. Obviously that doesn't make any code easier to understand. Here is an example with pi as a class and an instance method:
$ irb --simple-prompt
>> class Knowledge
>>   def pi
>>     3.14
>>   end
>>   def self.pi
>>     3.14159265359
>>   end
>> end
=> nil
>> Knowledge.pi
=> 3.14159265359
>> example = Knowledge.new
=> #<Knowledge:0x007f8ccc8786a0>
>> example.pi
=> 3.14
>> exit
$
List of All Instance Methods
You can read out all defined methods for a class with the method instance_methods. We try it out with the class This_and_that (first we create it once again in the irb):
$ irb --simple-prompt
>> class Knowledge
>>   def pi
>>     3.14
>>   end
>> end
=> nil
>> Knowledge.instance_methods
=> [:pi, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
>>
But that is much more than we have defined! Why? It's because Ruby gives every new class a basic set of methods by default. If we only want to list the methods that we have defined, then we can do it like this:
>> Knowledge.instance_methods(false)
=> [:pi]
>> exit
$

Updates about this book will be published on my Twitter feed.