OOP and Ruby 

Guillaume FAURE-DUMONT

@guillaume_fd

What is POO ?

Business coding !

  • Encapsulation

  • Inheritance

  • Polymorphism

POO principles

Encapsulation (1/6)

Define a concept:  CLASS

It's a whole that holds itself together with Properties:

  • Variables (data)
  • Methods (mechanism)

 

We can create instances of this concept: Objects

new_instance = Myclass.new

Constructor method:  initialize

Encapsulation (2/7)

class vehicle
    
    def initialize(wheels_number, speed)
        @wheels_number = wheels_number
        @speed = speed
        @position = 0
        @direction = 1
    end

    def describe
        puts "This vehicle has #{@wheels_number} wheels"
        puts "Position: #{@position} from origin"
    end

    def move_forward
        @position = @position + @speed * @direction
        puts "Position: #{@position} from origin"
    end

end

$ my_car = Vehicle.new(4, 150)
$ my_car.describe
This vehicle has 4 wheels
Position: 0 from origin
$ my_car.move_forward
Position: 100 from origin

Internal mechanism have to be ...internal !

"I don't care how you do it, just gimme the result"

 

Don't speak to strangers (law of Demeter)

 

Hide your mechanism with private & protected methods

Encapsulation (3/7)

Encapsulation (4/7)

class vehicle

    def describe
        puts "This vehicle has #{@wheels_number} wheels"
        write_position
    end

    def move_forward
        @position = @position + @speed * @direction
        write_position
    end

    private

        def write_position
            puts "Position: #{@position} from origin"
        end

end

$ my_car = Vehicle.new(4, 150)
$ my_car.write_position
NoMethodError: private method `write_position' called for #<Car:0x00000002d211b0>
$ my_car.describe
This vehicle has 4 wheels
Position: 0 from origin

Encapsulation (5/7)

Some code is only about the class and not it's instances

 

Math::PI

Math::E

 

WARNING:

    class methods cannot access instance attributes !

 

Encapsulation (6/7)

class Vehicle

  VERSION = 42.0

  @@vehicle_number = 0

  def initialize(wheels_number, speed)
    ...
    @@vehicle_number += 1

  end

  def describe
    ...
    self.class.display_vehicle_count
  end

  def self.display_vehicle_count
    puts "There are now #{@@vehicle_number} vehicle(s) in memory"
  end

end

$ Vehicle::VERSION
42.0
$ Vehicle::display_vehicle_count
There are now 0 vehicle(s) in memory

Encapsulation (7/7)

module Thp

    class Vehicle

      VERSION = 42.0
  
      ...

    end

end

Modules allow to gather Classes in bigger sets

Inheritance (1/2)

Think in Funnels

Start big, go into details with the flow

Create global concepts first

Car < Vehicle

 

and reuse ancestor's properties

(Don't Repeat Yourself)

Inheritance (2/2)

class Vehicle

    def initialize(wheels_number, speed)
        @wheels_number = wheels_number
        @speed = speed
    end

    ...
end


class Car < Vehicle

    def initialize(speed)
        @wheels_number = 4
        @speed = speed
    end
    
end


class Motocycle < Vehicle

    def initialize(speed)
        super 2, speed
    end

end

Polymorphism (1/2)

Having different reactions based on given parameters

 

and ... Overriding ;)

Polymorphism (2/2)

Having different reactions based on given parameters

class Train < Vehicle

  def initialize
    super 16, 2000
    @direction = 1
  end

  def set_direction(new_direction)
    puts 'This vehicle cannot change direction'
  end

  def move_forward
    @position = @position + @speed
    write_position
  end

end

Some Ruby Specifics

Having different reactions based on given parameters

# supervehicle.rb


class Vehicle

  def describe
    puts "\nThis vehicle is a #{self.class}"
    puts "Its superclass is #{self.class.superclass}"
    puts "It has #{@wheels_number} wheels"
    write_position
    self.class.display_vehicle_count
  end

end

OOP and Ruby

By Guillaume Faure-Dumont