main program

February 20, 2015 ยท View on GitHub

class PurchaseApprover

Implements the chain of responsibility pattern. Does not know anything

about the approval process, merely whether the current handler can approve

the request, or must pass it to a successor.

attr_reader :successor

def initialize successor @successor = successor end

def process_request request if approve_request request return elsif successor successor.process_request request else deny_request request end end

This may be overridden by a handler if it wants to provide a custom action

when it is the last member of the chain

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

class AmountApprover < PurchaseApprover

Base class for approvers who only consider whether the request amount is

allowable

BASE = 500

def approve_request request if request.amount < self.class::ALLOWABLE print_approval request return true else return false end end end

class Manager < AmountApprover ALLOWABLE = 10 * BASE

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

class Director < AmountApprover ALLOWABLE = 20 * BASE

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

class VicePresident < AmountApprover ALLOWABLE = 40 * BASE

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

class President < AmountApprover ALLOWABLE = 60 * BASE

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

class CFO < PurchaseApprover

An example of a handler that does not inherit from AmountApprover

Try adding it to the chain by implementing an annual budget that tracks the

total of all approved requests so far and whether we can afford one more.

def approve_request request if within_annual_budget? request puts "CFO will approve $#{request.amount}" return true else return false end end

def within_annual_budget? request # ... end end

class PurchaseRequest attr_reader :amount

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

class CLP def initialize(*approvers) approvers = build_approvers(approvers) @authority = approvers.first end

def process_request request @authority.process_request request end

private

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

main program

------------

approvers = CLP.new(Manager, Director, VicePresident, President)

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