#!/usr/bin/env ruby class Employee attr_reader :salary, :type, :taxtotal def initialize( salary, type ) @salary = salary @type = type end def computetaxbands case type # current tax rates are the same for single and married persons when 1 bandA = 2790 bandB = 32010 bandC = 150000 rateA = 0.1 rateB = 0.2 rateC = 0.4 rateD = 0.5 end case salary when 0..bandA calctax( IncomeTaxBand.new( salary, rateA ) ) when bandA+1..bandB calctax( IncomeTaxBand.new( salary, rateB ) ) when bandB+1..bandC calctax( IncomeTaxBand.new( bandB, rateB ), IncomeTaxBand.new( salary - bandB, rateC ) ) else calctax( IncomeTaxBand.new( bandB, rateB ), IncomeTaxBand.new( bandC, rateC ), IncomeTaxBand.new( salary - bandC, rateD ) ) end end def calctax( *taxbands ) #taxbands is an array of IncomeTaxBand objects @taxtotal = 0 taxband_inst = taxbands taxbands.each { | taxband_inst | @taxtotal += taxband_inst.tax } end end class IncomeTaxBand attr_reader :tax def initialize( amount, pct ) @tax = amount * pct end end class TaxViewer def inputvalid?(salary) if (salary.respond_to?(:match) && salary.match(/\d/)) true else false end end def annual(salary, tax) netannual = (salary - tax).round end def monthly(salary, tax) netmonthly = ((salary - tax) / 12).round end def weekly(salary, tax) netweekly = ((salary - tax) / 52).round end end puts "UK Income tax calculator (2013-2014):\n\n" loop do viewer = TaxViewer.new print "Please enter your gross annual Salary: £" salary = gets.chomp if viewer.inputvalid? salary emp = Employee.new(salary.to_i, 1) emp.computetaxbands printf "Total Tax: £%d\n", emp.taxtotal printf "Net Salary: £%d\n", viewer.annual(salary.to_i, emp.taxtotal) printf "Net Month: £%d\n", viewer.monthly(salary.to_i, emp.taxtotal) printf "Net Week: £%d\n", viewer.weekly(salary.to_i, emp.taxtotal) break else print "\nPlease enter a valid number!\n\n" end end
You can pull this code from Github for easier readability - please note that I am using 3 Classes -
1. Employee - reflecting a real world object
2. IncomeTaxBand - another real world object
3. TaxViewer - since Ruby encourages MVC, any viewer methods can be placed as an object too
This post is by no means any guide or tutorial - but if you need to ask me any queries please do. What I wanted to illustrate is an example of how a simple program which I personally used to undertake in a procedural approach in Bash or Perl in the past, can be made as OOP. The advantages of this design are too many to mention although some people might think it looks overbloated or complex.
1 comment:
This can be made more elegant by incorporating metaprogramming or reflection code on the computetaxbands method...but more on that in a future post!
Post a Comment