Code Reuse in Ruby
by Sava Virtosu
Code reuse aims to save time and resources and reduce redundancy by taking advantage of assets that have already been created in some form within the software product development process.
class Car
def drive
p 'Drive'
end
def color
p 'Black'
end
end
class RedCar < Car
def color
p 'Red'
end
end
class YellowCar < Car
def color
p 'Yellow'
end
end
car = Car.new
car.color
redCar = RedCar.new
redCar.colorApplicationController becomes a dumping ground of random methods that are needed by “a lot” of controllers - it’s effectively a global scope for code that doesn’t have an obvious place to go.
Framework (like rails) love Inheritance
developers don't :)
David Bryant Copeland
require 'rails_helper'
describe SomeModel do
# code
endrequire 'some_module'
class DummyObject
include SomeModule
end
describe "SomeModule" do
# code
end~ 7 sec
~ 0.2 sec
Framework overhead
module BlackColor
def color
p "Black"
end
end
module RedColor
def color
p "Red"
end
end
module YellowColor
def color
p "Yellow"
end
end class Car
include BlackColor
def drive
p "Drive"
end
end
class RedCar
include RedColor
def drive
p "Drive"
end
end
simpleCar = Car.new
simpleCar.color
simpleRedCar = RedCar.new
simpleRedCar.colorSimple Mixin
DCI (Data Context Interaction)
class Car
attr_reader :color_module
def initialize(color_module=:black)
@color_module = color_module
include_modules
end
def drive
p "Drive"
end
def include_modules
case @color_module
when :red
class << self
include RedColor
end
when :yellow
class << self
include YellowColor
end
when :black
class << self
include BlackColor
end
else
raise UnsupportedModule.new
end
end
endDynamic Mixin
blackCar = Car.new
blackCar.color
redCar = Car.new :red
redCar.colorDynamic Mixin
class Car
def drive
p "Drive"
end
end
class ColorModuleMapping
class UnsupportedModule < StandardError; end
def self.include_color_in(color=:black, object)
case color
when :red
class << object
include RedColor
end
when :yellow
class << object
include YellowColor
end
when :black
class << object
include BlackColor
end
else
raise UnsupportedModule.new
end
end
end
Dynamic Module Mapping Mixin
car = Car.new
ColorModuleMapping.include_color_in car
car.color
car = Car.new
ColorModuleMapping.include_color_in :red, car
car.colorDynamic Module Mapping Mixin
car = Car.new
ColorModuleMapping.include_color_in car unless car.respond_to? :color
car.colorThis is cool, because ruby is cool ^_^
↓
“composition” == “call methods on a private object”
Code reuse results in dependency on the component being reused.
class Car
attr_reader :color_obj
def initialize(color_obj)
@color_obj = color_obj
end
def color
color_obj.get_color
end
def drive
p "Drive"
end
end
class CarColor
attr_reader :color
def initialize(color=:black)
@color = color
end
def get_color
case @color
when :red
p 'Red'
when :yellow
p 'Yellow'
when :black
p 'Black'
end
end
end carColor = CarColor.new
car = Car.new carColor
car.color
carColor = CarColor.new :red
car = Car.new carColor
car.colorDependency Injection! (DHH will kill you XD)
class Car
attr_reader :color_obj
def build(color)
@color_obj = CarColor.new color
end
def initialize(color=:black)
build(color)
end
def color
color_obj.get_color
end
def drive
p "Drive"
end
end
blackCar = Car.new
blackCar.color
redCar = Car.new :red
redCar.colorConclusion: Hard to test
require 'memory_profiler'
report = MemoryProfiler.report do
# run your code here
end
report.pretty_print class Car
def drive
p 'Drive'
end
def color
p 'Black'
end
end
class RedCar < Car
def color
p 'Red'
end
end
class YellowCar < Car
def color
p 'Yellow'
end
end
car = Car.new
car.color
redCar = RedCar.new
redCar.color class Car
attr_reader :color_obj
def initialize(color_obj)
@color_obj = color_obj
end
def color
color_obj.get_color
end
def drive
p "Drive"
end
end
class CarColor
attr_reader :color
def initialize(color=:black)
@color = color
end
def get_color
case @color
when :red
p 'Red'
when :yellow
p 'Yellow'
when :black
p 'Black'
end
end
end class Car
include BlackColor
def drive
p "Drive"
end
end
class RedCar
include RedColor
def drive
p "Drive"
end
end
simpleCar = Car.new
simpleCar.color
simpleRedCar = RedCar.new
simpleRedCar.color module BlackColor
def color
p "Black"
end
end
module RedColor
def color
p "Red"
end
end
module YellowColor
def color
p "Yellow"
end
end class Car
attr_reader :color_module
def initialize(color_module=:black)
@color_module = color_module
include_modules
end
def drive
p "Drive"
end
def include_modules
case @color_module
when :red
class << self
include RedColor
end
when :yellow
class << self
include YellowColor
end
when :black
class << self
include BlackColor
end
else
raise UnsupportedModule.new
end
end
end class Car
def drive
p "Drive"
end
end
class ColorModuleMapping
class UnsupportedModule < StandardError; end
def self.include_color_in(color=:black, object)
case color
when :red
class << object
include RedColor
end
when :yellow
class << object
include YellowColor
end
when :black
class << object
include BlackColor
end
else
raise UnsupportedModule.new
end
end
end