Josh Thompson     about     blog     projects

Refactoring practice: Get rid of `attr_accessors` in `ogre.rb` in 2 minutes

Article Table of Contents


Preparing for Turing Series Index #

What follows is an eight-part series that will help you pick up useful information about a number of topics related to Ruby, specifically geared for students learning the Ruby programming language, as part of the Turing School’s Backend Software Development Program

It’s generally intended that you progress sequentially, but there’s no “right way” or “right order” to encounter these topics. You could convince me I have the order exactly backwards. I’d disagree, but only slightly.

I encourage you to skim around these chapters, get the “shape” of what’s to come, in your mind, and then dive in wherever you want. Good luck, and bug reports are welcome.


More refactoring practice!

I was reading Practical Object Oriented Design in Ruby, and then was looking at a Turing student’s work on the ogre mythical creature when I realized this was a perfect chance to explain a little about some principles of Object-Oriented Design.

Here’s a quick TWO MINUTE walk-through:

Here’s the code we’re starting with:

class Ogre
  attr_reader :name, :home, :swings, :encounter_counter
  def initialize(name, home = "Swamp")
    @name = name
    @home = home
    @swings = 0
    @encounter_counter = 0
  end
  
  def encounter(human)
    @encounter_counter += 1
    human.encounter_counter += 1
    if human.notices_ogre?
      swing_at(human)
    end
  end
  
  def swing_at(human)
    @swings += 1
  end
  
  def apologize(human)
    human.encounter_counter = 0
    @swings = 0
  end
end

class Human
  attr_accessor :encounter_counter
  attr_reader :name
  def initialize(name = "Jane")
    @name = name
    @encounter_counter = 0
  end
  
  def notices_ogre?
    return @encounter_counter % 3 == 0
  end
  
  def knocked_out?
    return true if encounter_counter >= 3
    false
  end
end

All tests pass.

I made changes to any time the Ogre class changed the “internal state” of another object (aka the Human class)

Copy-paste the code into your editor, and make the changes yourself!

The finished refactored version:

update: 👏 to Gaby Mendez for catching an error I made in the refactored code!

class Ogre
  attr_reader :name, :home, :swings, :encounter_counter
  def initialize(name, home = "Swamp")
    @name = name
    @home = home
    @swings = 0
    @encounter_counter = 0
  end
  
  def encounter(human)
    @encounter_counter += 1
    human.increment_encounters
    if human.notices_ogre?
      swing_at(human)
    end
  end
  
  def swing_at(human)
    @swings += 1
    # Gaby pointed out that the human needed to actually get knocked unconscious
    # at a certain point. Duh! I added this line in response:
    human.knock_unconscious if swings % 2 == 0
  end
  
  def apologize(human)
    # Gaby pointed out an error, so in fixing it I am deviating from the 
    # finished code in the video walkthrough. 
    human.revive
    @swings = 0
  end
end

class Human
  attr_reader :name, :encounter_counter, :knocked_out
  def initialize(name = "Jane")
    @name = name
    @encounter_counter = 0
    @knocked_out = false
  end
  
  def increment_encounters
    @encounter_counter += 1
  end
  
  def revive
    @encounter_counter = 0
    @knocked_out = false
  end
  
  def knock_unconscious
    @knocked_out = true
  end
  
  def notices_ogre?
    encounter_counter % 3 == 0
  end
  
  def knocked_out?
    # updated this a bit too. Sorry for the confusion!!!!!
    knocked_out
  end
end

Preparing for Turing Series Index #

What follows is an eight-part series that will help you pick up useful information about a number of topics related to Ruby, specifically geared for students learning the Ruby programming language, as part of the Turing School’s Backend Software Development Program

It’s generally intended that you progress sequentially, but there’s no “right way” or “right order” to encounter these topics. You could convince me I have the order exactly backwards. I’d disagree, but only slightly.

I encourage you to skim around these chapters, get the “shape” of what’s to come, in your mind, and then dive in wherever you want. Good luck, and bug reports are welcome.