Skip to content

Instantly share code, notes, and snippets.

@aruprakshit
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aruprakshit/797686aac92d498a2fac to your computer and use it in GitHub Desktop.
Save aruprakshit/797686aac92d498a2fac to your computer and use it in GitHub Desktop.
Chain-of-responsibility pattern in Ruby
module PurchasePower
BASE = 500
private
attr_accessor :successor
end
class Manager
include PurchasePower
ALLOWABLE = 10 * BASE
def process_request(request)
if request.amount < ALLOWABLE
puts("Manager will approve $#{request.amount}")
return
elsif !successor.nil?
successor.process_request(request)
end
end
end
class Director
include PurchasePower
ALLOWABLE = 20 * BASE
def process_request(request)
if request.amount < ALLOWABLE
puts("Director will approve $#{request.amount}")
return
elsif !successor.nil?
successor.process_request(request)
end
end
end
class VicePresident
include PurchasePower
ALLOWABLE = 40 * BASE
def process_request(request)
if request.amount < ALLOWABLE
puts("VicePresident will approve $#{request.amount}")
return
elsif !successor.nil?
successor.process_request(request)
end
end
end
class President
include PurchasePower
ALLOWABLE = 60 * BASE
def process_request(request)
if request.amount < ALLOWABLE
puts("President will approve $#{request.amount}")
return
else
puts "Your request for $#{request.amount} needs a board meeting!"
end
end
end
class PurchaseRequest
def initialize(number, amount, purpose)
@number = number
@amount = amount
@purpose = purpose
end
def amount
@amount
end
end
class Approvers
def initialize(*approvers)
@approvers = approvers.map(&:new)
end
def add_approver(approver)
@approvers << approver
end
def delete_approver(approver)
@approvers.delete(approver)
end
def approvers_list
@approvers
end
end
class CheckAuthority
def initialize(approvers)
@approvers = approvers
@starting_approver = build_chains.first
end
def checking
loop do
$stdout.flush
puts "Enter the amount to check who should approve your expenditure."
puts ">>"
@starting_approver.process_request PurchaseRequest.new(0, gets.to_i, 'General')
end
end
private
def build_chains
@approvers.each_cons(2).map { |prev_approver, next_approver| prev_approver.send :successor=, next_approver }
end
end
approvers = Approvers.new(Manager, Director, VicePresident, President)
CheckAuthority.new(approvers.approvers_list).checking
Arup-iMac:arup_ruby shreyas$ ruby a.rb
Enter the amount to check who should approve your expenditure.
>>
1200
Director will approve $1200
Enter the amount to check who should approve your expenditure.
>>
2000
Director will approve $2000
Enter the amount to check who should approve your expenditure.
>>
^[[A^[[B
Director will approve $0
Enter the amount to check who should approve your expenditure.
>>
3000
Director will approve $3000
Enter the amount to check who should approve your expenditure.
>>
40000
Your request for $40000 needs a board meeting!
Enter the amount to check who should approve your expenditure.
>>
4000
Director will approve $4000
Enter the amount to check who should approve your expenditure.
>>
30000
Your request for $30000 needs a board meeting!
Enter the amount to check who should approve your expenditure.
>>
10000
VicePresident will approve $10000
Enter the amount to check who should approve your expenditure.
>>
@aruprakshit
Copy link
Author

# this is written by @jhass. http://paste.mrzyx.de/pmpv58f1t/un5vrr/raw
module PurchasePower
  BASE = 500
  attr_reader :successor

  def initialize successor
    @successor = successor
  end

  def process_request request
    if request.amount < self.class::ALLOWABLE
      approve_request request
    elsif successor
      successor.process_request request
    else
      deny_request request
    end
  end
end

class Manager
  include PurchasePower

  ALLOWABLE = 10 * BASE

  def approve_request request
    puts "Manager will approve $#{request.amount}"
  end
end

class Director
  include PurchasePower

  ALLOWABLE = 20 * BASE

  def approve_request request
    puts "Director will approve $#{request.amount}"
  end
end

class VicePresident
  include PurchasePower

  ALLOWABLE = 40 * BASE

  def approve_request request
    puts "VicePresident will approve $#{request.amount}"
  end
end

class President
  include PurchasePower

  ALLOWABLE = 60 * BASE

  def approve_request request
    puts "President will approve $#{request.amount}"
  end

  def deny_request request
    puts "Your request for $#{request.amount} needs a board meeting!"
  end
end

class PurchaseRequest
  attr_reader :amount

  def initialize(number, amount, purpose)
    @number = number
    @amount = amount
    @purpose = purpose
  end
end

class CheckAuthority
  def initialize(starting_approver)
    @starting_approver = starting_approver
  end

  def check request
    @starting_approver.process_request request
  end
end

class CLI
  def initialize
    approvers = build_approvers(Manager, Director, VicePresident, President)
    @authority = CheckAuthority.new(approvers.first)
  end

  def run
    loop do
      $stdout.flush
      puts "Enter the amount to check who should approve your expenditure."
      print ">> "
      amount = gets.to_i
      @authority.check PurchaseRequest.new(0, amount, 'General')
    end
  end

  private def build_approvers(*approver_classes)
    [].tap do |approvers|
      approver_classes.reverse.inject(nil) {|successor, approver|
        approver.new(successor).tap {|approver| approvers.unshift approver }
      }
    end
  end
end

CLI.new.run

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