Skip to content

Instantly share code, notes, and snippets.

@msears
Created September 23, 2010 02:15
Show Gist options
  • Save msears/592960 to your computer and use it in GitHub Desktop.
Save msears/592960 to your computer and use it in GitHub Desktop.
class SquarePeg
attr_reader :width
def initialize(width)
@width = width
end
end
class RoundPeg
attr_reader :radius
def initialize(radius)
@radius = radius
end
end
class RoundHole
attr_reader :radius
def initialize(radius)
@radius = radius
end
def peg_fits?(peg)
peg.radius <= radius
end
end
class SquarePegAdaptor
def initialize(square_peg)
@peg = square_peg
end
def radius
Math.sqrt(((@peg.width/2)**2)*2)
end
end
hole = RoundHole.new(4.0)
4.upto(7) do |i|
peg = SquarePegAdaptor.new(SquarePeg.new(i.to_f))
if hole.peg_fits?(peg)
puts "peg #{peg} fits in hole #{hole}"
else
puts "peg #{peg} does not fit in hole"
end
end
class SquarePeg
attr_reader :width
def initialize(width)
@width = width
end
end
class RoundPeg
attr_reader :radius
def initialize(radius)
@radius = radius
end
end
class RoundHole
attr_reader :radius
def initialize(radius)
@radius = radius
end
def peg_fits?(peg)
peg.radius <= radius
end
end
class SquarePeg
def radius
Math.sqrt(((width/2)**2)*2)
end
end
hole = RoundHole.new(4.0)
4.upto(7) do |i|
peg = SquarePeg.new(i.to_f)
if hole.peg_fits?(peg)
puts "peg #{peg} fits in hole #{hole}"
else
puts "peg #{peg} does not fit in hole"
end
end
class CongaDancer
attr_reader :next_in_line
def initialize(next_in_line)
@next_in_line = next_in_line
end
def shimmy
puts "shimmy"
next_in_line.shimmy
end
def shake
next_in_line.shake
end
end
class CongaLeader
def shimmy
puts "shimmy!"
end
def shake
puts "shake!"
end
end
line = CongaDancer.new(CongaDancer.new(CongaLeader.new))
line.shimmy
line.shake
# Uses extend to dynamically add behaviour
class Coffee
def cost
2
end
end
module Whip
def cost
super + 0.2
end
end
module Sprinkles
def cost
super + 0.3
end
end
x = Coffee.new
x.extend Sprinkles
x.extend Whip
puts "Coffee with Sprinkles + Whip costs " + x.cost.to_s
# Uses with to get an even better API syntax
module Whip
def cost
super + 0.2
end
end
module Sprinkles
def cost
super + 0.3
end
end
class Coffee
def self.with(*args)
args.inject(self.new) {|memo, val| memo.extend val}
end
def cost
2
end
end
x = Coffee.with :sprinkles, :whip
x = Coffee.with Sprinkles, Whip
puts "Coffee with Sprinkles + Whip costs " + x.cost.to_s
class Coffee
def cost
2
end
end
module Decorator
def initialize(decorated)
@decorated = decorated
end
def method_missing(method, *args)
args.empty? ? @decorated.send(method) : @decorated.send(method, args)
end
end
# You can include this into any class you want to act as a decorator.
# You can then use that decorator as if it was the object it is decorating
# By default all messages sent to the decorator are forwarded on to the decorated object.
# You can then decorate the methods you need to extend:
class Milk
include Decorator
def cost
@decorated.cost + 0.4
end
end
# The real power of decorators lies in the fact that they can act like the objects they are decorating
# You can wrap decorators with other decorators as long as they share the same interface.
# By creating decorators for our different “extras”, we can create coffees using a combination of decorators and get the total cost of the coffee.
class Whip
include Decorator
def cost
@decorated.cost + 0.2
end
end
class Sprinkles
include Decorator
def cost
@decorated.cost + 0.3
end
end
puts "Coffee with Whip costs " + Whip.new(Coffee.new).cost.to_s
puts "Coffee with Milk + Whip + Sprinkes costs " + Sprinkles.new(Whip.new(Milk.new(Coffee.new))).cost.to_s
class CongaDancer
attr_reader :next_in_line
def initialize(next_in_line)
@next_in_line = next_in_line
end
def shimmy
puts "shimmy"
next_in_line.shimmy
end
def shake
next_in_line.shake
end
end
class CongaLeader < CongaDancer
def shimmy
puts "shimmy!"
end
def shake
puts "shake!"
end
end
class CongaDancer
def method_missing(name, *args)
puts "don't know how to #{name}, passing it on..."
next_in_line.__send__(name, *args)
end
end
class HokieCokieDancer < CongaDancer
def left
puts "left kick"
end
def right
puts "right kick"
end
def shake
puts "shake it all about"
next_in_line.shake
end
end
line = CongaLeader.new(HokieCokieDancer.new(CongaDancer.new))
puts "**********************"
line.left
puts "**********************"
line.right
puts "**********************"
line.left
puts "**********************"
line.right
puts "**********************"
line.shake
# Default/Typical approach is to use inheritance
class Coffee
def cost
2
end
end
class MilkCoffee < Coffee
def cost
2.4
end
end
class SweetCoffee < Coffee
def cost
2.15
end
end
class SweetMilkCoffee < Coffee
def cost
2.55
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment