POODR Ch 2 practice


Train of thought for POODR Ch 2

friend wants a calculator for gears:

Code from book

class Gear 
  attr_reader :chainring, :cog 
  def initialize( chainring, cog) 
    @chainring = chainring 
    @cog = cog 
  end 
  
  def ratio 
    chainring / cog.to_f 
  end 
end 

puts Gear.new( 52, 11).ratio # -> 4.72727272727273 
puts Gear.new( 30, 27).ratio # -> 1.11111111111111

Metz, Sandi (2012-09-05). Practical Object-Oriented Design in Ruby: An Agile Primer (Addison-Wesley Professional Ruby Series) (Kindle Locations 720-740). Pearson Education. Kindle Edition. 

    

friend wants to add gear_inches functionality:

Code from book

class Gear 
  attr_reader :chainring, :cog, :rim, :tire
  def initialize( chainring, cog, rim, tire) 
    @chainring = chainring 
    @cog       = cog 
    @rim       = rim
    @tire      = tire
  end 
  
  def ratio 
    chainring / cog.to_f 
  end 

  def gear_inches
    ratio * (rim + 2 * tire)
  end
end

puts Gear.new( 52, 11, 26, 1.5). gear_inches 
# -> 137.090909090909 22 23 
puts Gear.new( 52, 11, 24, 1.25). gear_inches 
# -> 125.272727272727

    

Gear.new(52, 11).ratio no longer works!

Code from book

puts Gear.new(52, 11).ratio 
# ArgumentError: wrong number of arguments (2 for 4)
# 	from gear.rb:3:in `initialize'
# 	from (irb):3:in `new'
# 	from (irb):3

    
Code from book

class Gear 
  attr_reader :chainring, :cog, :wheel
  def initialize( chainring, cog, rim, tire) 
    @chainring = chainring 
    @cog       = cog 
    @wheel     = Wheel.new(rim, tire)
  end 
  
  def ratio 
    chainring / cog.to_f 
  end 

  def gear_inches
    ratio * wheel.diameter
  end

  Wheel = Struct.new(:rim, :tire) do 
    def diameter
      rim + 2 * tire
    end
  end
end

    

Things to consider for changeable code

Info from book

## Write code that embraces change

* hide variables, use getters and setter not direct `@variable`
  * here `cog` is the only place that knows what `@cog/cog` means
  * ie, multiplying cog by `adj_factor` only requires `def cog; @cog * adj_factor; end`
  * your data can be thought of as plain old objects

* separate complex data structures with the information itself.

    

Final implementation from Ch 2 of Gear with Wheel

Info from book

class Gear 
  attr_reader :chainring, :cog, :wheel
  def initialize( chainring, cog, wheel=nil) 
    @chainring = chainring 
    @cog       = cog 
    @wheel     = wheel
  end 
  
  def ratio 
    chainring / cog.to_f 
  end 

  def gear_inches
    ratio * wheel.diameter
  end
end

class Wheel 
  attr_reader :rim, :tire
  def initialize(rim, tire)
    @rim  = rim
    @tire = tire
  end

  def diameter
    rim + 2 * tire
  end

  def circumference
    diameter * Math::PI
  end
end

    
Info from book

> @wheel = Wheel.new(26, 1.5)
 => #<Wheel:0x007f8f343d8ec8 @rim=26, @tire=1.5> 
> @wheel.diameter
 => 29.0 
> @wheel.circumference
 => 91.106186954104 
> Gear.new(52, 11).ratio
 => 4.7272727272727275 
> Gear.new(52, 11, @wheel).ratio
 => 4.7272727272727275 
> Gear.new(52, 11, @wheel).gear_inches
 => 137.0909090909091