# Liskov’s principle tends to be the most difficult to understand. The principle
# states that you should be able to replace any instances of a parent class
# with an instance of one of its children without creating any unexpected or
# incorrect behaviors.

class Rectangle
  def initialize(height, width)
    @height = height
    @width = width
  end

  def set_height(height)
    @height = height
  end

  def set_width(width)
    @width = width
  end

  def square
    @width * @height
  end
end

# Solution

# LSP says is if we know the interface of Rectangle, We need to be able to guess
# the interface of subtype class Square
# Square.new(3).square => 9

class Square < Rectangle
  def initialize(side)
    super(side, side)
  end

  def set_height(height)
    super(height)
    @width = height
  end

  def set_width(width)
    super(width)
    @height = width
  end
end

# Another common instance of a Liskov violation is raising an exception for an
# overridden method in a child class. It’s also not uncommon to see methods
# overridden with modified method signatures causing branching on type in
# classes that depend on objects of the parent’s type. All of these either
# lead to unstable code or unnecessary and ugly branching.

class Animal
  def walk
    'walking_as_animal'
  end
end

class Cat < Animal
  def run
    'run_as_cat'
  end
end

# Solution

class Animal
  def walk
    'walking_as_animal'
  end

  def run
    raise NotImplementedError
  end
end

class Cat < Animal
  def run
    'run_as_cat'
  end
end
