Skip to content

Instantly share code, notes, and snippets.

@benkoshy
Last active April 19, 2017 08:56
Show Gist options
  • Select an option

  • Save benkoshy/8774c855926818e2ecd141198273ff47 to your computer and use it in GitHub Desktop.

Select an option

Save benkoshy/8774c855926818e2ecd141198273ff47 to your computer and use it in GitHub Desktop.
A Gun Kata - problem on code review
class Gun
  attr_reader :smart_ammo

  def initialize(ammo)    
    @smart_ammo = SmartAmmo.at(ammo)
  end

  # how it sounds from start to finish
  def sound_of_the_whole_nine_yards
    sounds_of_gunfire = ""

    loop do
      # concatenate all the shots
      sounds_of_gunfire = sounds_of_gunfire + @smart_ammo.fire
      @smart_ammo = @smart_ammo.next_ammo
      break if @smart_ammo.ammo <= 0
    end

    puts sounds_of_gunfire
  end    
end

class SmartAmmo
  attr_reader :ammo

  def initialize(ammo)
    @ammo = ammo
  end

  def self.at(ammo)
    case ammo
    when 200..1000      
      CyclicAmmo.new(ammo)
    when 100..199      
      RapidAmmo.new(ammo)
    when 6..99            
      SustainedAmmo.new(ammo)
    when (1..5)      
      CeaseAmmo.new(ammo)
    else
      SmartAmmo.new(ammo)
    end
  end

  def next_ammo
    SmartAmmo.at(quantity_remaining_inventory)
  end

  def fire
      "#{speed}" + "#{output_remaining_inventory_after_consumption}"    
  end
  
  def speed
  end

  def quantity_remaining_inventory
  end

  def output_remaining_inventory_after_consumption    
    "SAW: #{quantity_remaining_inventory} rounds left!\n"       
  end
end

class CyclicAmmo < SmartAmmo
  def speed
    "CYCLIC FIRE\n" + "*MACHINE GUN NOISES*\n"    
  end

  def quantity_remaining_inventory
    @ammo - 5
  end
end

class RapidAmmo < SmartAmmo
  def speed
    "RAPID FIRE\n" + "*MACHINE GUN NOISES*\n"    
  end

  def quantity_remaining_inventory
     @ammo - 8
  end
end

class SustainedAmmo < SmartAmmo
  def speed
    "SUSTAINED FIRE\n" + "*MACHINE GUN NOISES*\n"    
  end

  def quantity_remaining_inventory
     @ammo - 4
  end
end

class CeaseAmmo < SmartAmmo
  def speed
    "CEASE FIRE\n"
  end

  def quantity_remaining_inventory
     -1
  end

  def output_remaining_inventory_after_consumption    
  end
end

Gun.new(200).sound_of_the_whole_nine_yards
@jknight1725
Copy link
Copy Markdown

I really appreciate you refactoring this from my codereview question
It helped me see the "Bigger Picture" and steered me in the right direction I feel.
Cheers!

@benkoshy
Copy link
Copy Markdown
Author

benkoshy commented Apr 13, 2017

@jknight1725 no worries mate glad i could help you out. I would strongly suggest you attempt to understand how we use polymorphism to supply behavoiur. as OOP programmers we don't want to be doing things like this:

if x == 2 THEN do this
If x == 3 THEN do this
if x  == 4 THEN do this.

As OOP programmers this is all we want to do:

cww = ClassWhichDoesWork.new(x)
cww.DoWork()

# and then we use a Factory method and polymorphism to supply the correct behaviour.
# we have no conditionals which say if x == 2 THEN do this. all of that is taken care of by polymorphism.
# if you do it that way you code will be very easy to maintain and to make changes, and to test as well.

I strongly, strongly recommend that you try to rewrite your code yourself and try to end up with the above code. If you are struggling then post a comment and perhaps when I get a spare moment I will create a video and show you how I did it from scratch.

Please note i just had a look at the method names i created: that's quite a bad example. you gotta carefully name methods and classes.

I learned how to do this by getting Sandi Metz 99 bottles book. It's well worth the purchase price.

btw....here is another example of the same type of thing: https://gist.github.com/BKSpurgeon/db4f8062569181d871f1565c89103e7e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment