Skip to content

Koans AboutInheritance

Polly Sileo edited this page Jun 6, 2015 · 1 revision
class AboutInheritance < Neo::Koan
  class Dog
    attr_reader :name

    def initialize(name)
      @name = name
    end

    def bark
      "WOOF"
    end
  end

  class Chihuahua < Dog
    def wag
      :happy
    end

    def bark
      "yip"
    end
  end

A class Dog was defined and a class Chihuahua was defined and declared to inherit from Dog. It will inherit all of the methods that Dog has.

  def test_subclasses_have_the_parent_as_an_ancestor
    assert_equal true, Chihuahua.ancestors.include?(Dog)
  end

  def test_all_classes_ultimately_inherit_from_object
    assert_equal true, Chihuahua.ancestors.include?(Object)
  end

Chihuahua has ancestors of Dog and Object

  def test_subclasses_inherit_behavior_from_parent_class
    chico = Chihuahua.new("Chico")
    assert_equal "Chico", chico.name
  end

We didn't initialize name in Chihuahua we didn't make it an attr_reader yet it when we call Chihuahua.new we pass it a name and that name is initialized. It is getting this behavior from the parent class - Dog.

  def test_subclasses_add_new_behavior
    chico = Chihuahua.new("Chico")
    assert_equal :happy, chico.wag

    assert_raise(NoMethodError) do
      fido = Dog.new("Fido")
      fido.wag
    end
  end

We created the wag method in the Chihuahua class. So Dog class doesn't know what it is. wag is a valid method call on Chihuahua and not on Dog. Child class has all the ancestor methods but the ancestor does not have the child methods.

  def test_subclasses_can_modify_existing_behavior
    chico = Chihuahua.new("Chico")
    assert_equal "yip", chico.bark

    fido = Dog.new("Fido")
    assert_equal "WOOF", fido.bark
  end

We can overwrite the method that the subclass inherited from the ancestor by creating a method of the same name. Chihuahua inherited the method bark from Dog so chico.bark would return ''' "WOOF" just like fido.bark ``` except that we defined a bark method in the Chihuahua class to return "yip" so this overrides what it inherited.

  class BullDog < Dog
    def bark
      super + ", GROWL"
    end
  end

  def test_subclasses_can_invoke_parent_behavior_via_super
    ralph = BullDog.new("Ralph")
    assert_equal "WOOF, GROWL", ralph.bark
  end

Super will grab what the ancestor class returns so we can add to it instead of overriding the whole thing.

  class GreatDane < Dog
    def growl
      super.bark + ", GROWL"
    end
  end

  def test_super_does_not_work_cross_method
    george = GreatDane.new("George")
    assert_raise(NoMethodError) do
      george.growl
    end
  end

end

You can not call super on a different method and pull it in. If you're calling super, the method of the parent class needs to have the same name. Here we throw an error because we are trying to call super.bark in the growl method.