Explaining S.O.L.I.D principles with Ruby code examples
Tags: ruby, beginners, webdev
Published: 2020-09-26 09:10:00

---
title: Explaining S.O.L.I.D principles with Ruby code examples
published: true
description: 
tags: #ruby #beginners #webdev
//cover_image: https://direct_url_to_image.jpg
---

Hello everyone, hope you week went well?

This week I will be giving code examples in ruby with reference to S.O.L.I.D principles explained in this article, [The S.O.L.I.D Principles in Pictures](https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898?_branch_match_id=745269505747235788) by **Ugonna Thelma**. This is the best I have seen so far that explains it with clear images. 

So what I am going to do it kind of show just code examples of her illustration in Ruby.

## S — Single Responsibility
```ruby
# don't do this

class JackOfAllTrade
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def cook
   "On it. #{name} is cooking your favorite food"
  end

  def garden
    "#{name} is planting new flowers in the garden"
  end

  def paint
    "#{name} is painting the walls in the sitting room"
  end

  def drive
    "#{name} is driving you to the airport"
  end
end

ngozi = JackOfAllTrade.new('Ngozi')
puts ngozi.cook
puts ngozi.garden
puts ngozi.paint
puts ngozi.drive

# => On it. Ngozi is cooking your favorite food
# => Ngozi is planting new flowers in the garden
# => Ngozi is painting the walls in the sitting room
# => Ngozi is driving you to the airport
```

```ruby
# do this instead

class Chef
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def cook
   "On it. #{name} is cooking your favorite food"
  end
end

class Gardener
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def garden
    "#{name} is planting new flowers in the garden"
  end
end

class Painter
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def paint
    "#{name} is painting the walls in the sitting room"
  end
end

class Driver
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def drive
    "#{name} is driving you to the airport"
  end
end

ngozi_the_chef = Chef.new('Ngozi')
ngozi_the_gardener = Gardener.new('Ngozi')
ngozi_the_painter = Painter.new('Ngozi')
ngozi_the_driver = Driver.new('Ngozi')

puts ngozi_the_chef.cook
puts ngozi_the_gardener.garden
puts ngozi_the_painter.paint
puts ngozi_the_driver.drive

# => On it. Ngozi is cooking your favorite food
# => Ngozi is planting new flowers in the garden
# => Ngozi is painting the walls in the sitting room
# => Ngozi is driving you to the airport

# these should throw an `undefined method` error because it doesn't perform that function

puts ngozi_the_chef.garden
# => undefined method `garden' for #<Chef:0x00007ff4918305d0 @name="Ngozi"> (NoMethodError)

# puts ngozi_the_gardener.paint
# puts ngozi_the_painter.drive
# puts ngozi_the_driver.cook
```

## O — Open-Closed
```ruby
# don't do this

class Chef
  def initialize(name)
    @name = name.capitalize
    @description = 'cooking a delicious meal'
  end

  def cook
    "#{@name} is #{@description}"
  end

  attr_writer :description
end

ngozi_the_chef = Chef.new('ngozi')
puts ngozi_the_chef.cook
ngozi_the_chef.description = 'painting the house'
puts ngozi_the_chef.cook

# => Ngozi is cooking a delicious meal
# => Ngozi is painting the house
```

```ruby
# do this instead

class Chef
  def initialize(name)
    @name = name.capitalize
  end

  def cook
    "#{@name} is cooking a delicious meal"
  end
end

class ChefAndPainter < Chef
  def paint
    "#{@name} is painting the walls in the sitting room"
  end
end

ngozi_the_chef = Chef.new('ngozi')
puts ngozi_the_chef.cook
ngozi_the_chef_and_painter = ChefAndPainter.new('ngozi')
puts ngozi_the_chef_and_painter.cook
puts ngozi_the_chef_and_painter.paint

# => Ngozi is cooking a delicious meal
# => Ngozi is cooking a delicious meal
# => Ngozi is painting the walls in the sitting room
```

## L — Liskov Substitution
```ruby
# don't do this

class Server
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def serve_coffee
   "I am #{name}. Here is your coffee"
  end

  def serve_water
    "I am #{name}. Here is your water"
  end
end

class ServerChild < Server
  undef_method :serve_coffee
end

lade = Server.new('lade')
puts lade.serve_coffee
evans = ServerChild.new('evans')
puts evans.serve_water
puts evans.serve_coffee

# => I am Lade. Here is your coffee
# => I am Evans. Here is your water
# => Traceback (most recent call last):
# => test.rb:45:in `<main>': undefined method `serve_coffee' for #<ServerChild:0x00007fc4ee851848 @name="Evans">
```

```ruby
# do this instead

class Server
  def initialize(name)
    @name = name.capitalize
  end

  attr_reader :name

  def serve_coffee
   "I am #{name}. Here is your coffee"
  end

  def serve_water
    "I am #{name}. Here is your water"
  end
end

class ServerChild < Server
  def serve_coffee
    "I am #{name}. Here is your cappucino"
  end
end

lade = Server.new('lade')
puts lade.serve_coffee
evans = ServerChild.new('evans')
puts evans.serve_water
puts evans.serve_coffee

# => I am Lade. Here is your coffee
# => I am Evans. Here is your water
# => I am Evans. Here is your cappucino
```

## I — Interface Segregation
```ruby
# don't do this

class Robot
  def initialize
    @no_of_arms = 2
    @no_of_antennas = 4
  end

  def spin_around
    'I can spin around'
  end

  def rotate_arm
    "I am rotating my #{@no_of_arms} arms"
  end

  def paint_house
    "Painting the house with my painting brush arm"
  end

  def search_for_stations
    "#{@no_of_antennas} antennas connecting to the closest radio station"
  end
end

class PainterRobot < Robot
end

class RadioRobot < Robot
end

# RadioRobot should not know anything about painting and PainterRobot shouldn't concern itself with searching for stations

puts RadioRobot.new.paint_house
puts PainterRobot.new.search_for_stations

# => Painting the house with my painting brush arm
# => 4 antennas connecting to the closest radio station
```

```ruby
# do this

class Robot
  def initialize
    @no_of_arms = 2
  end

  def spin_around
    'I can spin around'
  end

  def rotate_arm
    "I am rotating my #{@no_of_arms} arms"
  end
end

class PainterRobot < Robot
  def paint_house
   "Painting the house with my painting brush arm"
  end
end

class RadioRobot < Robot
  def initialize
    @no_of_antennas = 4
  end

  def search_for_stations
    "#{@no_of_antennas} antennas connecting to the closest radio station"
  end
end

puts RadioRobot.new.search_for_stations
puts PainterRobot.new.paint_house

# => 4 antennas connecting to the closest radio station
# => Painting the house with my painting brush arm
```

## D — Dependency Inversion
```ruby
# don't do this

class Robot
  def initialize
    @no_of_arms = 2
  end

  def spin_around
    'I can spin around'
  end

  def rotate_arm
    "I am rotating my #{@no_of_arms} arms"
  end
end

class PainterRobot < Robot
  def paint_house
   "Painting the house with my painting brush arm"
  end
end

puts PainterRobot.new.paint_house

# we want it to be able to paint with whatever tool we give it
# => Painting the house with my painting brush arm
```

```ruby
# do this 

class Robot
  def initialize
    @no_of_arms = 2
  end

  def spin_around
    'I can spin around'
  end

  def rotate_arm
    "I am rotating my #{@no_of_arms} arms"
  end
end

class PainterRobot < Robot
  def initialize(tool)
    @tool = tool
  end

  def paint_house
   "Painting the house with my #{@tool} arm"
  end
end

puts PainterRobot.new('painting brush').paint_house
puts PainterRobot.new('paint sprayer').paint_house
puts PainterRobot.new('paint roller').paint_house

# => Painting the house with my painting brush arm
# => Painting the house with my paint sprayer arm
# => Painting the house with my paint roller arm
```

That's it for this article. You can read through the main article to understand the concepts more.

Leave your comments and thoughts below. I would love to read them.

Until next week.